Minimal subset of the unbound sources.
This commit is contained in:
commit
b0cbd784b1
30
contrib/unbound/LICENSE
Normal file
30
contrib/unbound/LICENSE
Normal file
@ -0,0 +1,30 @@
|
||||
Copyright (c) 2007, 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.
|
1193
contrib/unbound/Makefile.in
Normal file
1193
contrib/unbound/Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
10
contrib/unbound/README
Normal file
10
contrib/unbound/README
Normal file
@ -0,0 +1,10 @@
|
||||
Unbound README
|
||||
* ./configure && make && make install
|
||||
* You can use libevent if you want. libevent is useful when using
|
||||
many (10000) outgoing ports. By default max 256 ports are opened at
|
||||
the same time and the builtin alternative is equally capable and a
|
||||
little faster.
|
||||
* More detailed README, README.svn, README.tests in doc directory
|
||||
* manual pages can be found in doc directory, and are installed, unbound(8).
|
||||
* example configuration file doc/example.conf
|
||||
|
122
contrib/unbound/ac_pkg_swig.m4
Normal file
122
contrib/unbound/ac_pkg_swig.m4
Normal file
@ -0,0 +1,122 @@
|
||||
# ===========================================================================
|
||||
# http://autoconf-archive.cryp.to/ac_pkg_swig.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AC_PROG_SWIG([major.minor.micro])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro searches for a SWIG installation on your system. If found you
|
||||
# should call SWIG via $(SWIG). You can use the optional first argument to
|
||||
# check if the version of the available SWIG is greater than or equal to
|
||||
# the value of the argument. It should have the format: N[.N[.N]] (N is a
|
||||
# number between 0 and 999. Only the first N is mandatory.)
|
||||
#
|
||||
# If the version argument is given (e.g. 1.3.17), AC_PROG_SWIG checks that
|
||||
# the swig package is this version number or higher.
|
||||
#
|
||||
# In configure.in, use as:
|
||||
#
|
||||
# AC_PROG_SWIG(1.3.17)
|
||||
# SWIG_ENABLE_CXX
|
||||
# SWIG_MULTI_MODULE_SUPPORT
|
||||
# SWIG_PYTHON
|
||||
#
|
||||
# LAST MODIFICATION
|
||||
#
|
||||
# 2008-04-12
|
||||
#
|
||||
# COPYLEFT
|
||||
#
|
||||
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
|
||||
# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
|
||||
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
|
||||
# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
|
||||
#
|
||||
# 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
|
||||
# Free Software Foundation; either version 2 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Macro Archive. When you make and
|
||||
# distribute a modified version of the Autoconf Macro, you may extend this
|
||||
# special exception to the GPL to apply to your modified version as well.
|
||||
|
||||
AC_DEFUN([AC_PROG_SWIG],[
|
||||
AC_PATH_PROG([SWIG],[swig])
|
||||
if test -z "$SWIG" ; then
|
||||
AC_MSG_WARN([cannot find 'swig' program. You should look at http://www.swig.org])
|
||||
SWIG='echo "Error: SWIG is not installed. You should look at http://www.swig.org" ; false'
|
||||
elif test -n "$1" ; then
|
||||
AC_MSG_CHECKING([for SWIG version])
|
||||
[swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
|
||||
AC_MSG_RESULT([$swig_version])
|
||||
if test -n "$swig_version" ; then
|
||||
# Calculate the required version number components
|
||||
[required=$1]
|
||||
[required_major=`echo $required | sed 's/[^0-9].*//'`]
|
||||
if test -z "$required_major" ; then
|
||||
[required_major=0]
|
||||
fi
|
||||
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
|
||||
[required_minor=`echo $required | sed 's/[^0-9].*//'`]
|
||||
if test -z "$required_minor" ; then
|
||||
[required_minor=0]
|
||||
fi
|
||||
[required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
|
||||
[required_patch=`echo $required | sed 's/[^0-9].*//'`]
|
||||
if test -z "$required_patch" ; then
|
||||
[required_patch=0]
|
||||
fi
|
||||
# Calculate the available version number components
|
||||
[available=$swig_version]
|
||||
[available_major=`echo $available | sed 's/[^0-9].*//'`]
|
||||
if test -z "$available_major" ; then
|
||||
[available_major=0]
|
||||
fi
|
||||
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
|
||||
[available_minor=`echo $available | sed 's/[^0-9].*//'`]
|
||||
if test -z "$available_minor" ; then
|
||||
[available_minor=0]
|
||||
fi
|
||||
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
|
||||
[available_patch=`echo $available | sed 's/[^0-9].*//'`]
|
||||
if test -z "$available_patch" ; then
|
||||
[available_patch=0]
|
||||
fi
|
||||
if test $available_major -ne $required_major \
|
||||
-o $available_minor -ne $required_minor \
|
||||
-o $available_patch -lt $required_patch ; then
|
||||
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version. You should look at http://www.swig.org])
|
||||
SWIG='echo "Error: SWIG version >= $1 is required. You have '"$swig_version"'. You should look at http://www.swig.org" ; false'
|
||||
else
|
||||
AC_MSG_NOTICE([SWIG executable is '$SWIG'])
|
||||
SWIG_LIB=`$SWIG -swiglib`
|
||||
AC_MSG_NOTICE([SWIG library directory is '$SWIG_LIB'])
|
||||
fi
|
||||
else
|
||||
AC_MSG_WARN([cannot determine SWIG version])
|
||||
SWIG='echo "Error: Cannot determine SWIG version. You should look at http://www.swig.org" ; false'
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([SWIG_LIB])
|
||||
])
|
8444
contrib/unbound/aclocal.m4
vendored
Normal file
8444
contrib/unbound/aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1370
contrib/unbound/acx_nlnetlabs.m4
Normal file
1370
contrib/unbound/acx_nlnetlabs.m4
Normal file
File diff suppressed because it is too large
Load Diff
280
contrib/unbound/acx_pthread.m4
Normal file
280
contrib/unbound/acx_pthread.m4
Normal file
@ -0,0 +1,280 @@
|
||||
##### http://autoconf-archive.cryp.to/acx_pthread.html
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro figures out how to build C programs using POSIX threads.
|
||||
# It sets the PTHREAD_LIBS output variable to the threads library and
|
||||
# linker flags, and the PTHREAD_CFLAGS output variable to any special
|
||||
# C compiler flags that are needed. (The user can also force certain
|
||||
# compiler flags/libs to be tested by setting these environment
|
||||
# variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise).
|
||||
# (This is necessary on AIX to use the special cc_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these
|
||||
# flags, but also link it with them as well. e.g. you should link
|
||||
# with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
|
||||
# $LIBS
|
||||
#
|
||||
# If you are only building threads programs, you may wish to use
|
||||
# these variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
|
||||
# constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
|
||||
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# ACTION-IF-FOUND is a list of shell commands to run if a threads
|
||||
# library is found, and ACTION-IF-NOT-FOUND is a list of commands to
|
||||
# run it if it is not found. If ACTION-IF-FOUND is not specified, the
|
||||
# default action will define HAVE_PTHREAD.
|
||||
#
|
||||
# Please let the authors know if this macro fails on any platform, or
|
||||
# if you have any other suggestions or comments. This macro was based
|
||||
# on work by SGJ on autoconf scripts for FFTW (http://www.fftw.org/)
|
||||
# (with help from M. Frigo), as well as ac_pthread and hb_pthread
|
||||
# macros posted by Alejandro Forero Cuervo to the autoconf macro
|
||||
# repository. We are also grateful for the helpful feedback of
|
||||
# numerous users.
|
||||
#
|
||||
# LAST MODIFICATION
|
||||
#
|
||||
# 2006-05-29
|
||||
#
|
||||
# COPYLEFT
|
||||
#
|
||||
# Copyright (c) 2006 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
#
|
||||
# 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 Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright
|
||||
# owner gives unlimited permission to copy, distribute and modify the
|
||||
# configure scripts that are the output of Autoconf when processing
|
||||
# the Macro. You need not follow the terms of the GNU General Public
|
||||
# License when using or distributing such scripts, even though
|
||||
# portions of the text of the Macro appear in them. The GNU General
|
||||
# Public License (GPL) does govern all other use of the material that
|
||||
# constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the
|
||||
# Autoconf Macro released by the Autoconf Macro Archive. When you
|
||||
# make and distribute a modified version of the Autoconf Macro, you
|
||||
# may extend this special exception to the GPL to apply to your
|
||||
# modified version as well.
|
||||
|
||||
AC_DEFUN([ACX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
acx_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||
AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
|
||||
AC_MSG_RESULT($acx_pthread_ok)
|
||||
if test x"$acx_pthread_ok" = xno; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
# names; the ordering is very important because some systems
|
||||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
|
||||
acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
||||
# pthreads: AIX (must check this before -lpthread)
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||
# -pthreads: Solaris/gcc
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case "${host_cpu}-${host_os}" in
|
||||
*solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
|
||||
acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test x"$acx_pthread_ok" = xno; then
|
||||
for flag in $acx_pthread_flags; do
|
||||
|
||||
case $flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
PTHREAD_CFLAGS="$flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
|
||||
if test x"$acx_pthread_config" = xno; then continue; fi
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
PTHREAD_LIBS="-l$flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
# need a special flag -Kthread to make this header compile.)
|
||||
# We check for pthread_join because it is in -lpthread on IRIX
|
||||
# while pthread_create is in libc. We check for pthread_attr_init
|
||||
# due to DEC craziness with -lpthreads. We check for
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
AC_TRY_LINK([#include <pthread.h>],
|
||||
[pthread_t th; pthread_join(th, 0);
|
||||
pthread_attr_init(0); pthread_cleanup_push(0, 0);
|
||||
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
|
||||
[acx_pthread_ok=yes])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
AC_MSG_RESULT($acx_pthread_ok)
|
||||
if test "x$acx_pthread_ok" = xyes; then
|
||||
break;
|
||||
fi
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
if test "x$acx_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
attr_name=unknown
|
||||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
|
||||
[attr_name=$attr; break])
|
||||
done
|
||||
AC_MSG_RESULT($attr_name)
|
||||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
case "${host_cpu}-${host_os}" in
|
||||
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
|
||||
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
|
||||
esac
|
||||
AC_MSG_RESULT(${flag})
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
# More AIX lossage: must compile with xlc_r or cc_r
|
||||
if test x"$GCC" != xyes; then
|
||||
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
|
||||
else
|
||||
PTHREAD_CC=$CC
|
||||
fi
|
||||
else
|
||||
PTHREAD_CC="$CC"
|
||||
fi
|
||||
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
AC_SUBST(PTHREAD_CFLAGS)
|
||||
AC_SUBST(PTHREAD_CC)
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$acx_pthread_ok" = xyes; then
|
||||
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
|
||||
:
|
||||
else
|
||||
acx_pthread_ok=no
|
||||
$2
|
||||
fi
|
||||
AC_LANG_RESTORE
|
||||
])dnl ACX_PTHREAD
|
200
contrib/unbound/acx_python.m4
Normal file
200
contrib/unbound/acx_python.m4
Normal file
@ -0,0 +1,200 @@
|
||||
AC_DEFUN([AC_PYTHON_DEVEL],[
|
||||
#
|
||||
# Allow the use of a (user set) custom python version
|
||||
#
|
||||
AC_ARG_VAR([PYTHON_VERSION],[The installed Python
|
||||
version to use, for example '2.3'. This string
|
||||
will be appended to the Python interpreter
|
||||
canonical name.])
|
||||
|
||||
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
|
||||
if test -z "$PYTHON"; then
|
||||
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
if test -z "$PYTHON_VERSION"; then
|
||||
PYTHON_VERSION=`$PYTHON -c "import sys, string; \
|
||||
print string.split(sys.version)[[0]]"`
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for a version of Python >= 2.1.0
|
||||
#
|
||||
AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
|
||||
ac_supports_python_ver=`$PYTHON -c "import sys, string; \
|
||||
ver = string.split(sys.version)[[0]]; \
|
||||
print ver >= '2.1.0'"`
|
||||
if test "$ac_supports_python_ver" != "True"; then
|
||||
if test -z "$PYTHON_NOVERSIONCHECK"; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_FAILURE([
|
||||
This version of the AC@&t@_PYTHON_DEVEL macro
|
||||
doesn't work properly with versions of Python before
|
||||
2.1.0. You may need to re-run configure, setting the
|
||||
variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG,
|
||||
PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
|
||||
Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
|
||||
to something else than an empty string.
|
||||
])
|
||||
else
|
||||
AC_MSG_RESULT([skip at user request])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
|
||||
#
|
||||
# if the macro parameter ``version'' is set, honour it
|
||||
#
|
||||
if test -n "$1"; then
|
||||
AC_MSG_CHECKING([for a version of Python $1])
|
||||
ac_supports_python_ver=`$PYTHON -c "import sys, string; \
|
||||
ver = string.split(sys.version)[[0]]; \
|
||||
print ver $1"`
|
||||
if test "$ac_supports_python_ver" = "True"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([this package requires Python $1.
|
||||
If you have it installed, but it isn't the default Python
|
||||
interpreter in your system path, please pass the PYTHON_VERSION
|
||||
variable to configure. See ``configure --help'' for reference.
|
||||
])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Check if you have distutils, else fail
|
||||
#
|
||||
AC_MSG_CHECKING([for the distutils Python package])
|
||||
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
|
||||
if test -z "$ac_distutils_result"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([cannot import Python module "distutils".
|
||||
Please check your Python installation. The error was:
|
||||
$ac_distutils_result])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for Python include path
|
||||
#
|
||||
AC_MSG_CHECKING([for Python include path])
|
||||
if test -z "$PYTHON_CPPFLAGS"; then
|
||||
python_path=`$PYTHON -c "import distutils.sysconfig; \
|
||||
print distutils.sysconfig.get_python_inc();"`
|
||||
if test -n "${python_path}"; then
|
||||
python_path="-I$python_path"
|
||||
fi
|
||||
PYTHON_CPPFLAGS=$python_path
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_CPPFLAGS])
|
||||
AC_SUBST([PYTHON_CPPFLAGS])
|
||||
|
||||
#
|
||||
# Check for Python library path
|
||||
#
|
||||
AC_MSG_CHECKING([for Python library path])
|
||||
if test -z "$PYTHON_LDFLAGS"; then
|
||||
# (makes two attempts to ensure we've got a version number
|
||||
# from the interpreter)
|
||||
py_version=`$PYTHON -c "from distutils.sysconfig import *; \
|
||||
from string import join; \
|
||||
print join(get_config_vars('VERSION'))"`
|
||||
if test "$py_version" = "[None]"; then
|
||||
if test -n "$PYTHON_VERSION"; then
|
||||
py_version=$PYTHON_VERSION
|
||||
else
|
||||
py_version=`$PYTHON -c "import sys; \
|
||||
print sys.version[[:3]]"`
|
||||
fi
|
||||
fi
|
||||
|
||||
PYTHON_LDFLAGS=`$PYTHON -c "from distutils.sysconfig import *; \
|
||||
from string import join; \
|
||||
print '-L' + get_python_lib(0,1), \
|
||||
'-L' + os.path.dirname(get_python_lib(0,1)), \
|
||||
'-lpython';"`$py_version
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_LDFLAGS])
|
||||
AC_SUBST([PYTHON_LDFLAGS])
|
||||
|
||||
#
|
||||
# Check for site packages
|
||||
#
|
||||
AC_MSG_CHECKING([for Python site-packages path])
|
||||
if test -z "$PYTHON_SITE_PKG"; then
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
|
||||
print distutils.sysconfig.get_python_lib(1,0);"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
||||
AC_SUBST([PYTHON_SITE_PKG])
|
||||
|
||||
#
|
||||
# libraries which must be linked in when embedding
|
||||
#
|
||||
AC_MSG_CHECKING(python extra libraries)
|
||||
if test -z "$PYTHON_EXTRA_LIBS"; then
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
|
||||
conf = distutils.sysconfig.get_config_var; \
|
||||
print conf('LOCALMODLIBS'), conf('LIBS')"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
|
||||
AC_SUBST(PYTHON_EXTRA_LIBS)
|
||||
|
||||
#
|
||||
# linking flags needed when embedding
|
||||
#
|
||||
AC_MSG_CHECKING(python extra linking flags)
|
||||
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
|
||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
|
||||
conf = distutils.sysconfig.get_config_var; \
|
||||
print conf('LINKFORSHARED')"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
||||
AC_SUBST(PYTHON_EXTRA_LDFLAGS)
|
||||
|
||||
#
|
||||
# final check to see if everything compiles alright
|
||||
#
|
||||
AC_MSG_CHECKING([consistency of all components of python development environment])
|
||||
AC_LANG_PUSH([C])
|
||||
# save current global flags
|
||||
LIBS="$ac_save_LIBS $PYTHON_LDFLAGS"
|
||||
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
|
||||
AC_TRY_LINK([
|
||||
#include <Python.h>
|
||||
],[
|
||||
Py_Initialize();
|
||||
],[pythonexists=yes],[pythonexists=no])
|
||||
|
||||
AC_MSG_RESULT([$pythonexists])
|
||||
|
||||
if test ! "$pythonexists" = "yes"; then
|
||||
AC_MSG_ERROR([
|
||||
Could not link test program to Python. Maybe the main Python library has been
|
||||
installed in some non-standard library path. If so, pass it to configure,
|
||||
via the LDFLAGS environment variable.
|
||||
Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
|
||||
============================================================================
|
||||
ERROR!
|
||||
You probably have to install the development version of the Python package
|
||||
for your distribution. The exact name of this package varies among them.
|
||||
============================================================================
|
||||
])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
AC_LANG_POP
|
||||
# turn back to default flags
|
||||
CPPFLAGS="$ac_save_CPPFLAGS"
|
||||
LIBS="$ac_save_LIBS"
|
||||
|
||||
#
|
||||
# all done!
|
||||
#
|
||||
])
|
||||
|
42
contrib/unbound/compat/ctime_r.c
Normal file
42
contrib/unbound/compat/ctime_r.c
Normal file
@ -0,0 +1,42 @@
|
||||
/* taken from ldns 1.6.1 */
|
||||
#include "config.h"
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include "util/locks.h"
|
||||
|
||||
/** the lock for ctime buffer */
|
||||
static lock_basic_t ctime_lock;
|
||||
/** has it been inited */
|
||||
static int ctime_r_init = 0;
|
||||
|
||||
/** cleanup ctime_r on exit */
|
||||
static void
|
||||
ctime_r_cleanup(void)
|
||||
{
|
||||
if(ctime_r_init) {
|
||||
ctime_r_init = 0;
|
||||
lock_basic_destroy(&ctime_lock);
|
||||
}
|
||||
}
|
||||
|
||||
char *ctime_r(const time_t *timep, char *buf)
|
||||
{
|
||||
char* result;
|
||||
if(!ctime_r_init) {
|
||||
/* still small race where this init can be done twice,
|
||||
* which is mostly harmless */
|
||||
ctime_r_init = 1;
|
||||
lock_basic_init(&ctime_lock);
|
||||
atexit(&ctime_r_cleanup);
|
||||
}
|
||||
lock_basic_lock(&ctime_lock);
|
||||
result = ctime(timep);
|
||||
if(buf && result) {
|
||||
if(strlen(result) > 10 && result[7]==' ' && result[8]=='0')
|
||||
result[8]=' '; /* fix error in windows ctime */
|
||||
strcpy(buf, result);
|
||||
}
|
||||
lock_basic_unlock(&ctime_lock);
|
||||
return result;
|
||||
}
|
227
contrib/unbound/compat/fake-rfc2553.c
Normal file
227
contrib/unbound/compat/fake-rfc2553.c
Normal file
@ -0,0 +1,227 @@
|
||||
/* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */
|
||||
/*
|
||||
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
|
||||
* Copyright (C) 1999 WIDE Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pseudo-implementation of RFC2553 name / address resolution functions
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For example, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "compat/fake-rfc2553.h"
|
||||
|
||||
#ifndef HAVE_GETNAMEINFO
|
||||
int getnameinfo(const struct sockaddr *sa, size_t ATTR_UNUSED(salen), char *host,
|
||||
size_t hostlen, char *serv, size_t servlen, int flags)
|
||||
{
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||
struct hostent *hp;
|
||||
char tmpserv[16];
|
||||
|
||||
if (serv != NULL) {
|
||||
snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
|
||||
if (strlcpy(serv, tmpserv, servlen) >= servlen)
|
||||
return (EAI_MEMORY);
|
||||
}
|
||||
|
||||
if (host != NULL) {
|
||||
if (flags & NI_NUMERICHOST) {
|
||||
if (strlcpy(host, inet_ntoa(sin->sin_addr),
|
||||
hostlen) >= hostlen)
|
||||
return (EAI_MEMORY);
|
||||
else
|
||||
return (0);
|
||||
} else {
|
||||
hp = gethostbyaddr((char *)&sin->sin_addr,
|
||||
sizeof(struct in_addr), AF_INET);
|
||||
if (hp == NULL)
|
||||
return (EAI_NODATA);
|
||||
|
||||
if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
|
||||
return (EAI_MEMORY);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
||||
#ifndef HAVE_GAI_STRERROR
|
||||
#ifdef HAVE_CONST_GAI_STRERROR_PROTO
|
||||
const char *
|
||||
#else
|
||||
char *
|
||||
#endif
|
||||
gai_strerror(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case EAI_NODATA:
|
||||
return ("no address associated with name");
|
||||
case EAI_MEMORY:
|
||||
return ("memory allocation failure.");
|
||||
case EAI_NONAME:
|
||||
return ("nodename nor servname provided, or not known");
|
||||
default:
|
||||
return ("unknown/invalid error.");
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#ifndef HAVE_FREEADDRINFO
|
||||
void
|
||||
freeaddrinfo(struct addrinfo *ai)
|
||||
{
|
||||
struct addrinfo *next;
|
||||
|
||||
for(; ai != NULL;) {
|
||||
next = ai->ai_next;
|
||||
free(ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
static struct
|
||||
addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints)
|
||||
{
|
||||
struct addrinfo *ai;
|
||||
|
||||
ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in));
|
||||
if (ai == NULL)
|
||||
return (NULL);
|
||||
|
||||
memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in));
|
||||
|
||||
ai->ai_addr = (struct sockaddr *)(ai + 1);
|
||||
/* XXX -- ssh doesn't use sa_len */
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
ai->ai_addr->sa_family = ai->ai_family = AF_INET;
|
||||
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
|
||||
|
||||
/* XXX: the following is not generally correct, but does what we want */
|
||||
if (hints->ai_socktype)
|
||||
ai->ai_socktype = hints->ai_socktype;
|
||||
else
|
||||
ai->ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (hints->ai_protocol)
|
||||
ai->ai_protocol = hints->ai_protocol;
|
||||
|
||||
return (ai);
|
||||
}
|
||||
|
||||
int
|
||||
getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
struct hostent *hp;
|
||||
struct servent *sp;
|
||||
struct in_addr in;
|
||||
int i;
|
||||
long int port;
|
||||
u_long addr;
|
||||
|
||||
port = 0;
|
||||
if (servname != NULL) {
|
||||
char *cp;
|
||||
|
||||
port = strtol(servname, &cp, 10);
|
||||
if (port > 0 && port <= 65535 && *cp == '\0')
|
||||
port = htons(port);
|
||||
else if ((sp = getservbyname(servname, NULL)) != NULL)
|
||||
port = sp->s_port;
|
||||
else
|
||||
port = 0;
|
||||
}
|
||||
|
||||
if (hints && hints->ai_flags & AI_PASSIVE) {
|
||||
addr = htonl(0x00000000);
|
||||
if (hostname && inet_aton(hostname, &in) != 0)
|
||||
addr = in.s_addr;
|
||||
*res = malloc_ai(port, addr, hints);
|
||||
if (*res == NULL)
|
||||
return (EAI_MEMORY);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!hostname) {
|
||||
*res = malloc_ai(port, htonl(0x7f000001), hints);
|
||||
if (*res == NULL)
|
||||
return (EAI_MEMORY);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (inet_aton(hostname, &in)) {
|
||||
*res = malloc_ai(port, in.s_addr, hints);
|
||||
if (*res == NULL)
|
||||
return (EAI_MEMORY);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Don't try DNS if AI_NUMERICHOST is set */
|
||||
if (hints && hints->ai_flags & AI_NUMERICHOST)
|
||||
return (EAI_NONAME);
|
||||
|
||||
hp = gethostbyname(hostname);
|
||||
if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
|
||||
struct addrinfo *cur, *prev;
|
||||
|
||||
cur = prev = *res = NULL;
|
||||
for (i = 0; hp->h_addr_list[i]; i++) {
|
||||
struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
|
||||
|
||||
cur = malloc_ai(port, in->s_addr, hints);
|
||||
if (cur == NULL) {
|
||||
if (*res != NULL)
|
||||
freeaddrinfo(*res);
|
||||
return (EAI_MEMORY);
|
||||
}
|
||||
if (prev)
|
||||
prev->ai_next = cur;
|
||||
else
|
||||
*res = cur;
|
||||
|
||||
prev = cur;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (EAI_NODATA);
|
||||
}
|
||||
#endif /* !HAVE_GETADDRINFO */
|
174
contrib/unbound/compat/fake-rfc2553.h
Normal file
174
contrib/unbound/compat/fake-rfc2553.h
Normal file
@ -0,0 +1,174 @@
|
||||
/* From openssh 4.3p2 filename openbsd-compat/fake-rfc2553.h */
|
||||
/*
|
||||
* Copyright (C) 2000-2003 Damien Miller. All rights reserved.
|
||||
* Copyright (C) 1999 WIDE Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pseudo-implementation of RFC2553 name / address resolution functions
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For example, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#ifndef _FAKE_RFC2553_H
|
||||
#define _FAKE_RFC2553_H
|
||||
|
||||
#include <config.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <limits.h>
|
||||
|
||||
/*
|
||||
* First, socket and INET6 related definitions
|
||||
*/
|
||||
#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
|
||||
# define _SS_MAXSIZE 128 /* Implementation specific max size */
|
||||
# define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr))
|
||||
struct sockaddr_storage {
|
||||
struct sockaddr ss_sa;
|
||||
char __ss_pad2[_SS_PADSIZE];
|
||||
};
|
||||
# define ss_family ss_sa.sa_family
|
||||
#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
|
||||
|
||||
#ifndef IN6_IS_ADDR_LOOPBACK
|
||||
# define IN6_IS_ADDR_LOOPBACK(a) \
|
||||
(((uint32_t *)(a))[0] == 0 && ((uint32_t *)(a))[1] == 0 && \
|
||||
((uint32_t *)(a))[2] == 0 && ((uint32_t *)(a))[3] == htonl(1))
|
||||
#endif /* !IN6_IS_ADDR_LOOPBACK */
|
||||
|
||||
#ifndef HAVE_STRUCT_IN6_ADDR
|
||||
struct in6_addr {
|
||||
uint8_t s6_addr[16];
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_IN6_ADDR */
|
||||
|
||||
#ifndef HAVE_STRUCT_SOCKADDR_IN6
|
||||
struct sockaddr_in6 {
|
||||
unsigned short sin6_family;
|
||||
uint16_t sin6_port;
|
||||
uint32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
|
||||
|
||||
#ifndef AF_INET6
|
||||
/* Define it to something that should never appear */
|
||||
#define AF_INET6 AF_MAX
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Next, RFC2553 name / address resolution API
|
||||
*/
|
||||
|
||||
#ifndef NI_NUMERICHOST
|
||||
# define NI_NUMERICHOST (1)
|
||||
#endif
|
||||
#ifndef NI_NAMEREQD
|
||||
# define NI_NAMEREQD (1<<1)
|
||||
#endif
|
||||
#ifndef NI_NUMERICSERV
|
||||
# define NI_NUMERICSERV (1<<2)
|
||||
#endif
|
||||
|
||||
#ifndef AI_PASSIVE
|
||||
# define AI_PASSIVE (1)
|
||||
#endif
|
||||
#ifndef AI_CANONNAME
|
||||
# define AI_CANONNAME (1<<1)
|
||||
#endif
|
||||
#ifndef AI_NUMERICHOST
|
||||
# define AI_NUMERICHOST (1<<2)
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
# define NI_MAXSERV 32
|
||||
#endif /* !NI_MAXSERV */
|
||||
#ifndef NI_MAXHOST
|
||||
# define NI_MAXHOST 1025
|
||||
#endif /* !NI_MAXHOST */
|
||||
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX 0xffffffff
|
||||
#endif
|
||||
|
||||
#ifndef EAI_NODATA
|
||||
# define EAI_NODATA (INT_MAX - 1)
|
||||
#endif
|
||||
#ifndef EAI_MEMORY
|
||||
# define EAI_MEMORY (INT_MAX - 2)
|
||||
#endif
|
||||
#ifndef EAI_NONAME
|
||||
# define EAI_NONAME (INT_MAX - 3)
|
||||
#endif
|
||||
#ifndef EAI_SYSTEM
|
||||
# define EAI_SYSTEM (INT_MAX - 4)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ADDRINFO
|
||||
struct addrinfo {
|
||||
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
|
||||
int ai_family; /* PF_xxx */
|
||||
int ai_socktype; /* SOCK_xxx */
|
||||
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
|
||||
size_t ai_addrlen; /* length of ai_addr */
|
||||
char *ai_canonname; /* canonical name for hostname */
|
||||
struct sockaddr *ai_addr; /* binary address */
|
||||
struct addrinfo *ai_next; /* next structure in linked list */
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_ADDRINFO */
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
#ifdef getaddrinfo
|
||||
# undef getaddrinfo
|
||||
#endif
|
||||
#define getaddrinfo(a,b,c,d) (getaddrinfo_unbound(a,b,c,d))
|
||||
int getaddrinfo(const char *, const char *,
|
||||
const struct addrinfo *, struct addrinfo **);
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO)
|
||||
#define gai_strerror(a) (gai_strerror_unbound(a))
|
||||
char *gai_strerror(int);
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#ifndef HAVE_FREEADDRINFO
|
||||
#define freeaddrinfo(a) (freeaddrinfo_unbound(a))
|
||||
void freeaddrinfo(struct addrinfo *);
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#ifndef HAVE_GETNAMEINFO
|
||||
#define getnameinfo(a,b,c,d,e,f,g) (getnameinfo_unbound(a,b,c,d,e,f,g))
|
||||
int getnameinfo(const struct sockaddr *, size_t, char *, size_t,
|
||||
char *, size_t, int);
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
||||
#endif /* !_FAKE_RFC2553_H */
|
||||
|
107
contrib/unbound/compat/gmtime_r.c
Normal file
107
contrib/unbound/compat/gmtime_r.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Taken from FreeBSD src / lib / libc / stdtime / localtime.c 1.43 revision.
|
||||
* localtime.c 7.78.
|
||||
* tzfile.h 1.8
|
||||
* adapted to be replacement gmtime_r.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#define MONSPERYEAR 12
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERMIN 60
|
||||
#define SECSPERHOUR (60*60)
|
||||
#define SECSPERDAY (24*60*60)
|
||||
#define DAYSPERWEEK 7
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||
|
||||
static const int mon_lengths[2][MONSPERYEAR] = {
|
||||
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
||||
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
};
|
||||
|
||||
static const int year_lengths[2] = {
|
||||
DAYSPERNYEAR, DAYSPERLYEAR
|
||||
};
|
||||
|
||||
static void
|
||||
timesub(timep, offset, tmp)
|
||||
const time_t * const timep;
|
||||
const long offset;
|
||||
struct tm * const tmp;
|
||||
{
|
||||
long days;
|
||||
long rem;
|
||||
long y;
|
||||
int yleap;
|
||||
const int * ip;
|
||||
|
||||
days = *timep / SECSPERDAY;
|
||||
rem = *timep % SECSPERDAY;
|
||||
rem += (offset);
|
||||
while (rem < 0) {
|
||||
rem += SECSPERDAY;
|
||||
--days;
|
||||
}
|
||||
while (rem >= SECSPERDAY) {
|
||||
rem -= SECSPERDAY;
|
||||
++days;
|
||||
}
|
||||
tmp->tm_hour = (int) (rem / SECSPERHOUR);
|
||||
rem = rem % SECSPERHOUR;
|
||||
tmp->tm_min = (int) (rem / SECSPERMIN);
|
||||
/*
|
||||
** A positive leap second requires a special
|
||||
** representation. This uses "... ??:59:60" et seq.
|
||||
*/
|
||||
tmp->tm_sec = (int) (rem % SECSPERMIN) ;
|
||||
tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
|
||||
if (tmp->tm_wday < 0)
|
||||
tmp->tm_wday += DAYSPERWEEK;
|
||||
y = EPOCH_YEAR;
|
||||
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
|
||||
while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
|
||||
long newy;
|
||||
|
||||
newy = y + days / DAYSPERNYEAR;
|
||||
if (days < 0)
|
||||
--newy;
|
||||
days -= (newy - y) * DAYSPERNYEAR +
|
||||
LEAPS_THRU_END_OF(newy - 1) -
|
||||
LEAPS_THRU_END_OF(y - 1);
|
||||
y = newy;
|
||||
}
|
||||
tmp->tm_year = y - TM_YEAR_BASE;
|
||||
tmp->tm_yday = (int) days;
|
||||
ip = mon_lengths[yleap];
|
||||
for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
|
||||
days = days - (long) ip[tmp->tm_mon];
|
||||
tmp->tm_mday = (int) (days + 1);
|
||||
tmp->tm_isdst = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-entrant version of gmtime.
|
||||
*/
|
||||
struct tm * gmtime_r(const time_t* timep, struct tm *tm)
|
||||
{
|
||||
timesub(timep, 0L, tm);
|
||||
return tm;
|
||||
}
|
182
contrib/unbound/compat/inet_aton.c
Normal file
182
contrib/unbound/compat/inet_aton.c
Normal file
@ -0,0 +1,182 @@
|
||||
/* From openssh4.3p2 compat/inet_aton.c */
|
||||
/*
|
||||
* Copyright (c) 1983, 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
* 3. Neither the name of the University 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 REGENTS 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.
|
||||
* -
|
||||
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies, and that
|
||||
* the name of Digital Equipment Corporation not be used in advertising or
|
||||
* publicity pertaining to distribution of the document or software without
|
||||
* specific, written prior permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
||||
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
||||
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
* -
|
||||
* --Copyright--
|
||||
*/
|
||||
|
||||
/* OPENBSD ORIGINAL: lib/libc/net/inet_addr.c */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if !defined(HAVE_INET_ATON)
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Ascii internet address interpretation routine.
|
||||
* The value returned is in network order.
|
||||
*/
|
||||
in_addr_t
|
||||
inet_addr(const char *cp)
|
||||
{
|
||||
struct in_addr val;
|
||||
|
||||
if (inet_aton(cp, &val))
|
||||
return (val.s_addr);
|
||||
return (INADDR_NONE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check whether "cp" is a valid ascii representation
|
||||
* of an Internet address and convert to a binary address.
|
||||
* Returns 1 if the address is valid, 0 if not.
|
||||
* This replaces inet_addr, the return value from which
|
||||
* cannot distinguish between failure and a local broadcast address.
|
||||
*/
|
||||
int
|
||||
inet_aton(const char *cp, struct in_addr *addr)
|
||||
{
|
||||
uint32_t val;
|
||||
int base, n;
|
||||
char c;
|
||||
unsigned int parts[4];
|
||||
unsigned int *pp = parts;
|
||||
|
||||
c = *cp;
|
||||
for (;;) {
|
||||
/*
|
||||
* Collect number up to ``.''.
|
||||
* Values are specified as for C:
|
||||
* 0x=hex, 0=octal, isdigit=decimal.
|
||||
*/
|
||||
if (!isdigit(c))
|
||||
return (0);
|
||||
val = 0; base = 10;
|
||||
if (c == '0') {
|
||||
c = *++cp;
|
||||
if (c == 'x' || c == 'X')
|
||||
base = 16, c = *++cp;
|
||||
else
|
||||
base = 8;
|
||||
}
|
||||
for (;;) {
|
||||
if (isascii(c) && isdigit(c)) {
|
||||
val = (val * base) + (c - '0');
|
||||
c = *++cp;
|
||||
} else if (base == 16 && isascii(c) && isxdigit(c)) {
|
||||
val = (val << 4) |
|
||||
(c + 10 - (islower(c) ? 'a' : 'A'));
|
||||
c = *++cp;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (c == '.') {
|
||||
/*
|
||||
* Internet format:
|
||||
* a.b.c.d
|
||||
* a.b.c (with c treated as 16 bits)
|
||||
* a.b (with b treated as 24 bits)
|
||||
*/
|
||||
if (pp >= parts + 3)
|
||||
return (0);
|
||||
*pp++ = val;
|
||||
c = *++cp;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Check for trailing characters.
|
||||
*/
|
||||
if (c != '\0' && (!isascii(c) || !isspace(c)))
|
||||
return (0);
|
||||
/*
|
||||
* Concoct the address according to
|
||||
* the number of parts specified.
|
||||
*/
|
||||
n = pp - parts + 1;
|
||||
switch (n) {
|
||||
|
||||
case 0:
|
||||
return (0); /* initial nondigit */
|
||||
|
||||
case 1: /* a -- 32 bits */
|
||||
break;
|
||||
|
||||
case 2: /* a.b -- 8.24 bits */
|
||||
if ((val > 0xffffff) || (parts[0] > 0xff))
|
||||
return (0);
|
||||
val |= parts[0] << 24;
|
||||
break;
|
||||
|
||||
case 3: /* a.b.c -- 8.8.16 bits */
|
||||
if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff))
|
||||
return (0);
|
||||
val |= (parts[0] << 24) | (parts[1] << 16);
|
||||
break;
|
||||
|
||||
case 4: /* a.b.c.d -- 8.8.8.8 bits */
|
||||
if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff))
|
||||
return (0);
|
||||
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
|
||||
break;
|
||||
}
|
||||
if (addr)
|
||||
addr->s_addr = htonl(val);
|
||||
return (1);
|
||||
}
|
||||
|
||||
#endif /* !defined(HAVE_INET_ATON) */
|
218
contrib/unbound/compat/inet_ntop.c
Normal file
218
contrib/unbound/compat/inet_ntop.c
Normal file
@ -0,0 +1,218 @@
|
||||
/* From openssh 4.3p2 compat/inet_ntop.c */
|
||||
/* Copyright (c) 1996 by Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* OPENBSD ORIGINAL: lib/libc/net/inet_ntop.c */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifndef HAVE_INET_NTOP
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef IN6ADDRSZ
|
||||
#define IN6ADDRSZ 16 /* IPv6 T_AAAA */
|
||||
#endif
|
||||
|
||||
#ifndef INT16SZ
|
||||
#define INT16SZ 2 /* for systems without 16-bit ints */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* WARNING: Don't even consider trying to compile this on a system where
|
||||
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
|
||||
*/
|
||||
|
||||
static const char *inet_ntop4(const u_char *src, char *dst, size_t size);
|
||||
static const char *inet_ntop6(const u_char *src, char *dst, size_t size);
|
||||
|
||||
/* char *
|
||||
* inet_ntop(af, src, dst, size)
|
||||
* convert a network format address to presentation format.
|
||||
* return:
|
||||
* pointer to presentation format address (`dst'), or NULL (see errno).
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
const char *
|
||||
inet_ntop(int af, const void *src, char *dst, size_t size)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return (inet_ntop4(src, dst, size));
|
||||
case AF_INET6:
|
||||
return (inet_ntop6(src, dst, size));
|
||||
default:
|
||||
#ifdef EAFNOSUPPORT
|
||||
errno = EAFNOSUPPORT;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
#endif
|
||||
return (NULL);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* const char *
|
||||
* inet_ntop4(src, dst, size)
|
||||
* format an IPv4 address, more or less like inet_ntoa()
|
||||
* return:
|
||||
* `dst' (as a const)
|
||||
* notes:
|
||||
* (1) uses no statics
|
||||
* (2) takes a u_char* not an in_addr as input
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static const char *
|
||||
inet_ntop4(const u_char *src, char *dst, size_t size)
|
||||
{
|
||||
static const char fmt[] = "%u.%u.%u.%u";
|
||||
char tmp[sizeof "255.255.255.255"];
|
||||
int l;
|
||||
|
||||
l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]);
|
||||
if (l <= 0 || l >= (int)size) {
|
||||
errno = ENOSPC;
|
||||
return (NULL);
|
||||
}
|
||||
strlcpy(dst, tmp, size);
|
||||
return (dst);
|
||||
}
|
||||
|
||||
/* const char *
|
||||
* inet_ntop6(src, dst, size)
|
||||
* convert IPv6 binary address into presentation (printable) format
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static const char *
|
||||
inet_ntop6(const u_char *src, char *dst, size_t size)
|
||||
{
|
||||
/*
|
||||
* Note that int32_t and int16_t need only be "at least" large enough
|
||||
* to contain a value of the specified size. On some systems, like
|
||||
* Crays, there is no such thing as an integer variable with 16 bits.
|
||||
* Keep this in mind if you think this function should have been coded
|
||||
* to use pointer overlays. All the world's not a VAX.
|
||||
*/
|
||||
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
|
||||
char *tp, *ep;
|
||||
struct { int base, len; } best, cur;
|
||||
u_int words[IN6ADDRSZ / INT16SZ];
|
||||
int i;
|
||||
int advance;
|
||||
|
||||
/*
|
||||
* Preprocess:
|
||||
* Copy the input (bytewise) array into a wordwise array.
|
||||
* Find the longest run of 0x00's in src[] for :: shorthanding.
|
||||
*/
|
||||
memset(words, '\0', sizeof words);
|
||||
for (i = 0; i < IN6ADDRSZ; i++)
|
||||
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
|
||||
best.base = -1;
|
||||
best.len = 0;
|
||||
cur.base = -1;
|
||||
cur.len = 0;
|
||||
for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
|
||||
if (words[i] == 0) {
|
||||
if (cur.base == -1)
|
||||
cur.base = i, cur.len = 1;
|
||||
else
|
||||
cur.len++;
|
||||
} else {
|
||||
if (cur.base != -1) {
|
||||
if (best.base == -1 || cur.len > best.len)
|
||||
best = cur;
|
||||
cur.base = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cur.base != -1) {
|
||||
if (best.base == -1 || cur.len > best.len)
|
||||
best = cur;
|
||||
}
|
||||
if (best.base != -1 && best.len < 2)
|
||||
best.base = -1;
|
||||
|
||||
/*
|
||||
* Format the result.
|
||||
*/
|
||||
tp = tmp;
|
||||
ep = tmp + sizeof(tmp);
|
||||
for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) {
|
||||
/* Are we inside the best run of 0x00's? */
|
||||
if (best.base != -1 && i >= best.base &&
|
||||
i < (best.base + best.len)) {
|
||||
if (i == best.base) {
|
||||
if (tp + 1 >= ep)
|
||||
return (NULL);
|
||||
*tp++ = ':';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* Are we following an initial run of 0x00s or any real hex? */
|
||||
if (i != 0) {
|
||||
if (tp + 1 >= ep)
|
||||
return (NULL);
|
||||
*tp++ = ':';
|
||||
}
|
||||
/* Is this address an encapsulated IPv4? */
|
||||
if (i == 6 && best.base == 0 &&
|
||||
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
|
||||
if (!inet_ntop4(src+12, tp, (size_t)(ep - tp)))
|
||||
return (NULL);
|
||||
tp += strlen(tp);
|
||||
break;
|
||||
}
|
||||
advance = snprintf(tp, ep - tp, "%x", words[i]);
|
||||
if (advance <= 0 || advance >= ep - tp)
|
||||
return (NULL);
|
||||
tp += advance;
|
||||
}
|
||||
/* Was it a trailing run of 0x00's? */
|
||||
if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) {
|
||||
if (tp + 1 >= ep)
|
||||
return (NULL);
|
||||
*tp++ = ':';
|
||||
}
|
||||
if (tp + 1 >= ep)
|
||||
return (NULL);
|
||||
*tp++ = '\0';
|
||||
|
||||
/*
|
||||
* Check for overflow, copy, and we're done.
|
||||
*/
|
||||
if ((size_t)(tp - tmp) > size) {
|
||||
errno = ENOSPC;
|
||||
return (NULL);
|
||||
}
|
||||
strlcpy(dst, tmp, size);
|
||||
return (dst);
|
||||
}
|
||||
|
||||
#endif /* !HAVE_INET_NTOP */
|
230
contrib/unbound/compat/inet_pton.c
Normal file
230
contrib/unbound/compat/inet_pton.c
Normal file
@ -0,0 +1,230 @@
|
||||
/* $KAME: inet_pton.c,v 1.5 2001/08/20 02:32:40 itojun Exp $ */
|
||||
|
||||
/* Copyright (c) 1996 by Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* WARNING: Don't even consider trying to compile this on a system where
|
||||
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
|
||||
*/
|
||||
|
||||
static int inet_pton4 (const char *src, uint8_t *dst);
|
||||
static int inet_pton6 (const char *src, uint8_t *dst);
|
||||
|
||||
/*
|
||||
*
|
||||
* The definitions we might miss.
|
||||
*
|
||||
*/
|
||||
#ifndef NS_INT16SZ
|
||||
#define NS_INT16SZ 2
|
||||
#endif
|
||||
|
||||
#ifndef NS_IN6ADDRSZ
|
||||
#define NS_IN6ADDRSZ 16
|
||||
#endif
|
||||
|
||||
#ifndef NS_INADDRSZ
|
||||
#define NS_INADDRSZ 4
|
||||
#endif
|
||||
|
||||
/* int
|
||||
* inet_pton(af, src, dst)
|
||||
* convert from presentation format (which usually means ASCII printable)
|
||||
* to network format (which is usually some kind of binary format).
|
||||
* return:
|
||||
* 1 if the address was valid for the specified address family
|
||||
* 0 if the address wasn't valid (`dst' is untouched in this case)
|
||||
* -1 if some other error occurred (`dst' is untouched in this case, too)
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
int
|
||||
inet_pton(af, src, dst)
|
||||
int af;
|
||||
const char *src;
|
||||
void *dst;
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return (inet_pton4(src, dst));
|
||||
case AF_INET6:
|
||||
return (inet_pton6(src, dst));
|
||||
default:
|
||||
#ifdef EAFNOSUPPORT
|
||||
errno = EAFNOSUPPORT;
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* int
|
||||
* inet_pton4(src, dst)
|
||||
* like inet_aton() but without all the hexadecimal and shorthand.
|
||||
* return:
|
||||
* 1 if `src' is a valid dotted quad, else 0.
|
||||
* notice:
|
||||
* does not touch `dst' unless it's returning 1.
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static int
|
||||
inet_pton4(src, dst)
|
||||
const char *src;
|
||||
uint8_t *dst;
|
||||
{
|
||||
static const char digits[] = "0123456789";
|
||||
int saw_digit, octets, ch;
|
||||
uint8_t tmp[NS_INADDRSZ], *tp;
|
||||
|
||||
saw_digit = 0;
|
||||
octets = 0;
|
||||
*(tp = tmp) = 0;
|
||||
while ((ch = *src++) != '\0') {
|
||||
const char *pch;
|
||||
|
||||
if ((pch = strchr(digits, ch)) != NULL) {
|
||||
uint32_t new = *tp * 10 + (pch - digits);
|
||||
|
||||
if (new > 255)
|
||||
return (0);
|
||||
*tp = new;
|
||||
if (! saw_digit) {
|
||||
if (++octets > 4)
|
||||
return (0);
|
||||
saw_digit = 1;
|
||||
}
|
||||
} else if (ch == '.' && saw_digit) {
|
||||
if (octets == 4)
|
||||
return (0);
|
||||
*++tp = 0;
|
||||
saw_digit = 0;
|
||||
} else
|
||||
return (0);
|
||||
}
|
||||
if (octets < 4)
|
||||
return (0);
|
||||
|
||||
memcpy(dst, tmp, NS_INADDRSZ);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* int
|
||||
* inet_pton6(src, dst)
|
||||
* convert presentation level address to network order binary form.
|
||||
* return:
|
||||
* 1 if `src' is a valid [RFC1884 2.2] address, else 0.
|
||||
* notice:
|
||||
* (1) does not touch `dst' unless it's returning 1.
|
||||
* (2) :: in a full address is silently ignored.
|
||||
* credit:
|
||||
* inspired by Mark Andrews.
|
||||
* author:
|
||||
* Paul Vixie, 1996.
|
||||
*/
|
||||
static int
|
||||
inet_pton6(src, dst)
|
||||
const char *src;
|
||||
uint8_t *dst;
|
||||
{
|
||||
static const char xdigits_l[] = "0123456789abcdef",
|
||||
xdigits_u[] = "0123456789ABCDEF";
|
||||
uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
|
||||
const char *xdigits, *curtok;
|
||||
int ch, saw_xdigit;
|
||||
uint32_t val;
|
||||
|
||||
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
|
||||
endp = tp + NS_IN6ADDRSZ;
|
||||
colonp = NULL;
|
||||
/* Leading :: requires some special handling. */
|
||||
if (*src == ':')
|
||||
if (*++src != ':')
|
||||
return (0);
|
||||
curtok = src;
|
||||
saw_xdigit = 0;
|
||||
val = 0;
|
||||
while ((ch = *src++) != '\0') {
|
||||
const char *pch;
|
||||
|
||||
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
|
||||
pch = strchr((xdigits = xdigits_u), ch);
|
||||
if (pch != NULL) {
|
||||
val <<= 4;
|
||||
val |= (pch - xdigits);
|
||||
if (val > 0xffff)
|
||||
return (0);
|
||||
saw_xdigit = 1;
|
||||
continue;
|
||||
}
|
||||
if (ch == ':') {
|
||||
curtok = src;
|
||||
if (!saw_xdigit) {
|
||||
if (colonp)
|
||||
return (0);
|
||||
colonp = tp;
|
||||
continue;
|
||||
}
|
||||
if (tp + NS_INT16SZ > endp)
|
||||
return (0);
|
||||
*tp++ = (uint8_t) (val >> 8) & 0xff;
|
||||
*tp++ = (uint8_t) val & 0xff;
|
||||
saw_xdigit = 0;
|
||||
val = 0;
|
||||
continue;
|
||||
}
|
||||
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
|
||||
inet_pton4(curtok, tp) > 0) {
|
||||
tp += NS_INADDRSZ;
|
||||
saw_xdigit = 0;
|
||||
break; /* '\0' was seen by inet_pton4(). */
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if (saw_xdigit) {
|
||||
if (tp + NS_INT16SZ > endp)
|
||||
return (0);
|
||||
*tp++ = (uint8_t) (val >> 8) & 0xff;
|
||||
*tp++ = (uint8_t) val & 0xff;
|
||||
}
|
||||
if (colonp != NULL) {
|
||||
/*
|
||||
* Since some memmove()'s erroneously fail to handle
|
||||
* overlapping regions, we'll do the shift by hand.
|
||||
*/
|
||||
const int n = tp - colonp;
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= n; i++) {
|
||||
endp[- i] = colonp[n - i];
|
||||
colonp[n - i] = 0;
|
||||
}
|
||||
tp = endp;
|
||||
}
|
||||
if (tp != endp)
|
||||
return (0);
|
||||
memcpy(dst, tmp, NS_IN6ADDRSZ);
|
||||
return (1);
|
||||
}
|
19
contrib/unbound/compat/malloc.c
Normal file
19
contrib/unbound/compat/malloc.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* Just a replacement, if the original malloc is not
|
||||
GNU-compliant. See autoconf documentation. */
|
||||
|
||||
#include "config.h"
|
||||
#undef malloc
|
||||
#include <sys/types.h>
|
||||
|
||||
void *malloc ();
|
||||
|
||||
/* Allocate an N-byte block of memory from the heap.
|
||||
If N is zero, allocate a 1-byte block. */
|
||||
|
||||
void *
|
||||
rpl_malloc_unbound (size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
n = 1;
|
||||
return malloc (n);
|
||||
}
|
25
contrib/unbound/compat/memcmp.c
Normal file
25
contrib/unbound/compat/memcmp.c
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* memcmp.c: memcmp compat implementation.
|
||||
*
|
||||
* Copyright (c) 2010, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* See LICENSE for the license.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
int memcmp(const void *x, const void *y, size_t n);
|
||||
|
||||
int memcmp(const void *x, const void *y, size_t n)
|
||||
{
|
||||
const uint8_t* x8 = (const uint8_t*)x;
|
||||
const uint8_t* y8 = (const uint8_t*)y;
|
||||
size_t i;
|
||||
for(i=0; i<n; i++) {
|
||||
if(x8[i] < y8[i])
|
||||
return -1;
|
||||
else if(x8[i] > y8[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
16
contrib/unbound/compat/memcmp.h
Normal file
16
contrib/unbound/compat/memcmp.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* memcmp.h: undef memcmp for compat.
|
||||
*
|
||||
* Copyright (c) 2012, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* See LICENSE for the license.
|
||||
*/
|
||||
#ifndef COMPAT_MEMCMP_H
|
||||
#define COMPAT_MEMCMP_H
|
||||
|
||||
#ifdef memcmp
|
||||
/* undef here otherwise autoheader messes it up in config.h */
|
||||
# undef memcmp
|
||||
#endif
|
||||
|
||||
#endif /* COMPAT_MEMCMP_H */
|
43
contrib/unbound/compat/memmove.c
Normal file
43
contrib/unbound/compat/memmove.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* memmove.c: memmove compat implementation.
|
||||
*
|
||||
* Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
|
||||
*
|
||||
* See LICENSE for the license.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n);
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n)
|
||||
{
|
||||
uint8_t* from = (uint8_t*) src;
|
||||
uint8_t* to = (uint8_t*) dest;
|
||||
|
||||
if (from == to || n == 0)
|
||||
return dest;
|
||||
if (to > from && to-from < (int)n) {
|
||||
/* to overlaps with from */
|
||||
/* <from......> */
|
||||
/* <to........> */
|
||||
/* copy in reverse, to avoid overwriting from */
|
||||
int i;
|
||||
for(i=n-1; i>=0; i--)
|
||||
to[i] = from[i];
|
||||
return dest;
|
||||
}
|
||||
if (from > to && from-to < (int)n) {
|
||||
/* to overlaps with from */
|
||||
/* <from......> */
|
||||
/* <to........> */
|
||||
/* copy forwards, to avoid overwriting from */
|
||||
size_t i;
|
||||
for(i=0; i<n; i++)
|
||||
to[i] = from[i];
|
||||
return dest;
|
||||
}
|
||||
memcpy(dest, src, n);
|
||||
return dest;
|
||||
}
|
792
contrib/unbound/compat/snprintf.c
Normal file
792
contrib/unbound/compat/snprintf.c
Normal file
@ -0,0 +1,792 @@
|
||||
#include <config.h>
|
||||
|
||||
#ifndef HAVE_SNPRINTF
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Define this as a fall through, HAVE_STDARG_H is probably already set */
|
||||
|
||||
#define HAVE_VARARGS_H
|
||||
|
||||
/**************************************************************
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Wouter Wijngaards(wouter@nlnetlabs.nl) 2/09/2010 for unbound.
|
||||
* Limited support for %g. Does not do the exponents for the before-dot.
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
|
||||
/* varargs declarations: */
|
||||
|
||||
#if defined(HAVE_STDARG_H)
|
||||
# include <stdarg.h>
|
||||
# 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 <varargs.h>
|
||||
# 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
|
||||
|
||||
int snprintf (char *str, size_t count, const char *fmt, ...);
|
||||
int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
|
||||
|
||||
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, int conv);
|
||||
static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
|
||||
|
||||
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
|
||||
{
|
||||
str[0] = 0;
|
||||
dopr(str, count, fmt, args);
|
||||
return(strlen(str));
|
||||
}
|
||||
|
||||
/* VARARGS3 */
|
||||
#ifdef HAVE_STDARGS
|
||||
int snprintf (char *str,size_t count,const char *fmt,...)
|
||||
#else
|
||||
int snprintf (va_alist) va_dcl
|
||||
#endif
|
||||
{
|
||||
#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
|
||||
*/
|
||||
|
||||
/* 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')
|
||||
#ifndef MAX
|
||||
#define MAX(p,q) ((p >= q) ? p : q)
|
||||
#endif
|
||||
|
||||
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(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(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, 'f');
|
||||
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);
|
||||
fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags, 'g');
|
||||
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 = "<NULL>";
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/* 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 long double compat_pow10 (int exp)
|
||||
{
|
||||
long double result = 1;
|
||||
|
||||
while (exp)
|
||||
{
|
||||
result *= 10;
|
||||
exp--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static long compat_round (long 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 conv)
|
||||
{
|
||||
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
|
||||
|
||||
intpart = ufvalue;
|
||||
|
||||
/*
|
||||
* 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 = compat_round ((compat_pow10 (max)) * (ufvalue - intpart));
|
||||
|
||||
if (fracpart >= compat_pow10 (max))
|
||||
{
|
||||
intpart++;
|
||||
fracpart -= compat_pow10 (max);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SNPRINTF
|
||||
dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
|
||||
#endif
|
||||
|
||||
/* Convert integer part */
|
||||
do {
|
||||
iconvert[iplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
|
||||
intpart = (intpart / 10);
|
||||
} while(intpart && (iplace < 20));
|
||||
if (iplace == 20) iplace--;
|
||||
iconvert[iplace] = 0;
|
||||
|
||||
/* Convert fractional part */
|
||||
do {
|
||||
fconvert[fplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
|
||||
fracpart = (fracpart / 10);
|
||||
if(conv == 'g' && fplace == 1 && fconvert[0] == '0') {
|
||||
fplace = 0; /* skip trailing zeroes for %g */
|
||||
zpadlen ++;
|
||||
}
|
||||
} while(fracpart && (fplace < 20));
|
||||
if (fplace == 20) fplace--;
|
||||
fconvert[fplace] = 0;
|
||||
|
||||
if(conv == 'f') {
|
||||
/* -1 for decimal point, another -1 if we are printing a sign */
|
||||
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
|
||||
zpadlen = max - fplace;
|
||||
} else if(conv == 'g') {
|
||||
/* zpadlen contains number of trailing zeroes removed */
|
||||
padlen = min - iplace - (max-zpadlen) - 1 - ((signvalue) ? 1 : 0);
|
||||
if(fplace == 0) {
|
||||
padlen += 1; /* add the decimal dot suppressed */
|
||||
zpadlen = 0;
|
||||
} else zpadlen = (max-zpadlen) - fplace;
|
||||
}
|
||||
if (zpadlen < 0)
|
||||
zpadlen = 0;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (flags & DP_F_MINUS)
|
||||
padlen = -padlen; /* Left Justifty */
|
||||
|
||||
if ((flags & DP_F_ZERO) && (padlen > 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]);
|
||||
|
||||
/* for %g do not output decimal point if no fraction is present */
|
||||
if(conv == 'f' || (conv == 'g' && fplace > 0)) {
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
#endif /* SNPRINTF_TEST */
|
||||
|
||||
#endif /* !HAVE_SNPRINTF */
|
57
contrib/unbound/compat/strlcpy.c
Normal file
57
contrib/unbound/compat/strlcpy.c
Normal file
@ -0,0 +1,57 @@
|
||||
/* from openssh 4.3p2 compat/strlcpy.c */
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */
|
||||
|
||||
#include <config.h>
|
||||
#ifndef HAVE_STRLCPY
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0 && --n != 0) {
|
||||
do {
|
||||
if ((*d++ = *s++) == 0)
|
||||
break;
|
||||
} while (--n != 0);
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
|
||||
#endif /* !HAVE_STRLCPY */
|
345
contrib/unbound/compat/strptime.c
Normal file
345
contrib/unbound/compat/strptime.c
Normal file
@ -0,0 +1,345 @@
|
||||
/** strptime workaround (for oa macos leopard)
|
||||
* This strptime follows the man strptime (2001-11-12)
|
||||
* conforming to SUSv2, POSIX.1-2001
|
||||
*
|
||||
* This very simple version of strptime has no:
|
||||
* - E alternatives
|
||||
* - O alternatives
|
||||
* - Glibc additions
|
||||
* - Does not process week numbers
|
||||
* - Does not properly processes year day
|
||||
*
|
||||
* LICENSE
|
||||
* Copyright (c) 2008, NLnet Labs, Matthijs Mekking
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NLnetLabs 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 COPYRIGHT OWNER 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 "config.h"
|
||||
|
||||
#ifndef HAVE_CONFIG_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifndef STRPTIME_WORKS
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *abb_weekdays[] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
|
||||
};
|
||||
static const char *full_weekdays[] = {
|
||||
"Sunday", "Monday", "Tuesday", "Wednesday",
|
||||
"Thursday", "Friday", "Saturday", NULL
|
||||
};
|
||||
static const char *abb_months[] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
|
||||
};
|
||||
static const char *full_months[] = {
|
||||
"January", "February", "March", "April", "May", "June",
|
||||
"July", "August", "September", "October", "November", "December", NULL
|
||||
};
|
||||
static const char *ampm[] = {
|
||||
"am", "pm", NULL
|
||||
};
|
||||
|
||||
static int
|
||||
match_string(const char **buf, const char **strs)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; strs[i] != NULL; i++) {
|
||||
int len = strlen(strs[i]);
|
||||
if (strncasecmp (*buf, strs[i], len) == 0) {
|
||||
*buf += len;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
str2int(const char **buf, int max)
|
||||
{
|
||||
int ret=0, count=0;
|
||||
|
||||
while (*buf[0] != '\0' && isdigit(*buf[0]) && count<max) {
|
||||
ret = ret*10 + (*buf[0] - '0');
|
||||
(*buf)++;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Converts the character string s to values which are stored in tm
|
||||
* using the format specified by format
|
||||
**/
|
||||
char *
|
||||
unbound_strptime(const char *s, const char *format, struct tm *tm)
|
||||
{
|
||||
int c, ret;
|
||||
int split_year = 0;
|
||||
|
||||
while ((c = *format) != '\0') {
|
||||
/* whitespace, literal or format */
|
||||
if (isspace(c)) { /* whitespace */
|
||||
/** whitespace matches zero or more whitespace characters in the
|
||||
* input string.
|
||||
**/
|
||||
while (isspace(*s))
|
||||
s++;
|
||||
}
|
||||
else if (c == '%') { /* format */
|
||||
format++;
|
||||
c = *format;
|
||||
switch (c) {
|
||||
case '%': /* %% is converted to % */
|
||||
if (*s != c) {
|
||||
return NULL;
|
||||
}
|
||||
s++;
|
||||
break;
|
||||
case 'a': /* weekday name, abbreviated or full */
|
||||
case 'A':
|
||||
ret = match_string(&s, full_weekdays);
|
||||
if (ret < 0)
|
||||
ret = match_string(&s, abb_weekdays);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_wday = ret;
|
||||
break;
|
||||
case 'b': /* month name, abbreviated or full */
|
||||
case 'B':
|
||||
case 'h':
|
||||
ret = match_string(&s, full_months);
|
||||
if (ret < 0)
|
||||
ret = match_string(&s, abb_months);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_mon = ret;
|
||||
break;
|
||||
case 'c': /* date and time representation */
|
||||
if (!(s = unbound_strptime(s, "%x %X", tm))) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'C': /* century number */
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 0 || ret > 99) { /* must be in [00,99] */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (split_year) {
|
||||
tm->tm_year = ret*100 + (tm->tm_year%100);
|
||||
}
|
||||
else {
|
||||
tm->tm_year = ret*100 - TM_YEAR_BASE;
|
||||
split_year = 1;
|
||||
}
|
||||
break;
|
||||
case 'd': /* day of month */
|
||||
case 'e':
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 1 || ret > 31) { /* must be in [01,31] */
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_mday = ret;
|
||||
break;
|
||||
case 'D': /* equivalent to %m/%d/%y */
|
||||
if (!(s = unbound_strptime(s, "%m/%d/%y", tm))) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'H': /* hour */
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 0 || ret > 23) { /* must be in [00,23] */
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_hour = ret;
|
||||
break;
|
||||
case 'I': /* 12hr clock hour */
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 1 || ret > 12) { /* must be in [01,12] */
|
||||
return NULL;
|
||||
}
|
||||
if (ret == 12) /* actually [0,11] */
|
||||
ret = 0;
|
||||
tm->tm_hour = ret;
|
||||
break;
|
||||
case 'j': /* day of year */
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 1 || ret > 366) { /* must be in [001,366] */
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_yday = ret;
|
||||
break;
|
||||
case 'm': /* month */
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 1 || ret > 12) { /* must be in [01,12] */
|
||||
return NULL;
|
||||
}
|
||||
/* months go from 0-11 */
|
||||
tm->tm_mon = (ret-1);
|
||||
break;
|
||||
case 'M': /* minute */
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 0 || ret > 59) { /* must be in [00,59] */
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_min = ret;
|
||||
break;
|
||||
case 'n': /* arbitrary whitespace */
|
||||
case 't':
|
||||
while (isspace(*s))
|
||||
s++;
|
||||
break;
|
||||
case 'p': /* am pm */
|
||||
ret = match_string(&s, ampm);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (tm->tm_hour < 0 || tm->tm_hour > 11) { /* %I */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ret == 1) /* pm */
|
||||
tm->tm_hour += 12;
|
||||
break;
|
||||
case 'r': /* equivalent of %I:%M:%S %p */
|
||||
if (!(s = unbound_strptime(s, "%I:%M:%S %p", tm))) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'R': /* equivalent of %H:%M */
|
||||
if (!(s = unbound_strptime(s, "%H:%M", tm))) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'S': /* seconds */
|
||||
ret = str2int(&s, 2);
|
||||
/* 60 may occur for leap seconds */
|
||||
/* earlier 61 was also allowed */
|
||||
if (ret < 0 || ret > 60) { /* must be in [00,60] */
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_sec = ret;
|
||||
break;
|
||||
case 'T': /* equivalent of %H:%M:%S */
|
||||
if (!(s = unbound_strptime(s, "%H:%M:%S", tm))) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'U': /* week number, with the first Sun of Jan being w1 */
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 0 || ret > 53) { /* must be in [00,53] */
|
||||
return NULL;
|
||||
}
|
||||
/** it is hard (and not necessary for nsd) to determine time
|
||||
* data from week number.
|
||||
**/
|
||||
break;
|
||||
case 'w': /* day of week */
|
||||
ret = str2int(&s, 1);
|
||||
if (ret < 0 || ret > 6) { /* must be in [0,6] */
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_wday = ret;
|
||||
break;
|
||||
case 'W': /* week number, with the first Mon of Jan being w1 */
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 0 || ret > 53) { /* must be in [00,53] */
|
||||
return NULL;
|
||||
}
|
||||
/** it is hard (and not necessary for nsd) to determine time
|
||||
* data from week number.
|
||||
**/
|
||||
break;
|
||||
case 'x': /* date format */
|
||||
if (!(s = unbound_strptime(s, "%m/%d/%y", tm))) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'X': /* time format */
|
||||
if (!(s = unbound_strptime(s, "%H:%M:%S", tm))) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case 'y': /* last two digits of a year */
|
||||
ret = str2int(&s, 2);
|
||||
if (ret < 0 || ret > 99) { /* must be in [00,99] */
|
||||
return NULL;
|
||||
}
|
||||
if (split_year) {
|
||||
tm->tm_year = ((tm->tm_year/100) * 100) + ret;
|
||||
}
|
||||
else {
|
||||
split_year = 1;
|
||||
|
||||
/** currently:
|
||||
* if in [0,68] we are in 21th century,
|
||||
* if in [69,99] we are in 20th century.
|
||||
**/
|
||||
if (ret < 69) /* 2000 */
|
||||
ret += 100;
|
||||
tm->tm_year = ret;
|
||||
}
|
||||
break;
|
||||
case 'Y': /* year */
|
||||
ret = str2int(&s, 4);
|
||||
if (ret < 0 || ret > 9999) {
|
||||
return NULL;
|
||||
}
|
||||
tm->tm_year = ret - TM_YEAR_BASE;
|
||||
break;
|
||||
case '\0':
|
||||
default: /* unsupported, cannot match format */
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { /* literal */
|
||||
/* if input cannot match format, return NULL */
|
||||
if (*s != c)
|
||||
return NULL;
|
||||
s++;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
|
||||
/* return pointer to remainder of s */
|
||||
return (char*) s;
|
||||
}
|
||||
|
||||
#endif /* STRPTIME_WORKS */
|
1501
contrib/unbound/config.guess
vendored
Executable file
1501
contrib/unbound/config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
899
contrib/unbound/config.h.in
Normal file
899
contrib/unbound/config.h.in
Normal file
@ -0,0 +1,899 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Directory to chroot to */
|
||||
#undef CHROOT_DIR
|
||||
|
||||
/* Pathname to the Unbound configuration file */
|
||||
#undef CONFIGFILE
|
||||
|
||||
/* configure flags */
|
||||
#undef CONFIGURE_BUILD_WITH
|
||||
|
||||
/* configure date */
|
||||
#undef CONFIGURE_DATE
|
||||
|
||||
/* configure target system */
|
||||
#undef CONFIGURE_TARGET
|
||||
|
||||
/* Define this if on macOSX10.4-darwin8 and setreuid and setregid do not work
|
||||
*/
|
||||
#undef DARWIN_BROKEN_SETREUID
|
||||
|
||||
/* Whether daemon is deprecated */
|
||||
#undef DEPRECATED_DAEMON
|
||||
|
||||
/* Define if you want to use debug lock checking (slow). */
|
||||
#undef ENABLE_LOCK_CHECKS
|
||||
|
||||
/* Define this if you enabled-allsymbols from libunbound to link binaries to
|
||||
it for smaller install size, but the libunbound export table is polluted by
|
||||
internal symbols */
|
||||
#undef EXPORT_ALL_SYMBOLS
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Whether the C compiler accepts the "format" attribute */
|
||||
#undef HAVE_ATTR_FORMAT
|
||||
|
||||
/* Whether the C compiler accepts the "unused" attribute */
|
||||
#undef HAVE_ATTR_UNUSED
|
||||
|
||||
/* Define to 1 if your system has a working `chown' function. */
|
||||
#undef HAVE_CHOWN
|
||||
|
||||
/* Define to 1 if you have the `chroot' function. */
|
||||
#undef HAVE_CHROOT
|
||||
|
||||
/* Define to 1 if you have the `ctime_r' function. */
|
||||
#undef HAVE_CTIME_R
|
||||
|
||||
/* Define to 1 if you have the `daemon' function. */
|
||||
#undef HAVE_DAEMON
|
||||
|
||||
/* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_NID_SECP384R1
|
||||
|
||||
/* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0
|
||||
if you don't. */
|
||||
#undef HAVE_DECL_NID_X9_62_PRIME256V1
|
||||
|
||||
/* Define to 1 if you have the declaration of `sk_SSL_COMP_pop_free', and to 0
|
||||
if you don't. */
|
||||
#undef HAVE_DECL_SK_SSL_COMP_POP_FREE
|
||||
|
||||
/* Define to 1 if you have the declaration of
|
||||
`SSL_COMP_get_compression_methods', and to 0 if you don't. */
|
||||
#undef HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the `event_base_free' function. */
|
||||
#undef HAVE_EVENT_BASE_FREE
|
||||
|
||||
/* Define to 1 if you have the `event_base_get_method' function. */
|
||||
#undef HAVE_EVENT_BASE_GET_METHOD
|
||||
|
||||
/* Define to 1 if you have the `event_base_new' function. */
|
||||
#undef HAVE_EVENT_BASE_NEW
|
||||
|
||||
/* Define to 1 if you have the `event_base_once' function. */
|
||||
#undef HAVE_EVENT_BASE_ONCE
|
||||
|
||||
/* Define to 1 if you have the <event.h> header file. */
|
||||
#undef HAVE_EVENT_H
|
||||
|
||||
/* Define to 1 if you have the `EVP_sha1' function. */
|
||||
#undef HAVE_EVP_SHA1
|
||||
|
||||
/* Define to 1 if you have the `EVP_sha256' function. */
|
||||
#undef HAVE_EVP_SHA256
|
||||
|
||||
/* Define to 1 if you have the `EVP_sha512' function. */
|
||||
#undef HAVE_EVP_SHA512
|
||||
|
||||
/* Define to 1 if you have the `ev_default_loop' function. */
|
||||
#undef HAVE_EV_DEFAULT_LOOP
|
||||
|
||||
/* Define to 1 if you have the `ev_loop' function. */
|
||||
#undef HAVE_EV_LOOP
|
||||
|
||||
/* Define to 1 if you have the <expat.h> header file. */
|
||||
#undef HAVE_EXPAT_H
|
||||
|
||||
/* Define to 1 if you have the `fcntl' function. */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
|
||||
#undef HAVE_FSEEKO
|
||||
|
||||
/* Whether getaddrinfo is available */
|
||||
#undef HAVE_GETADDRINFO
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
|
||||
/* Define to 1 if you have the `getpwnam' function. */
|
||||
#undef HAVE_GETPWNAM
|
||||
|
||||
/* Define to 1 if you have the `getrlimit' function. */
|
||||
#undef HAVE_GETRLIMIT
|
||||
|
||||
/* Define to 1 if you have the `glob' function. */
|
||||
#undef HAVE_GLOB
|
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
#undef HAVE_GLOB_H
|
||||
|
||||
/* Define to 1 if you have the `gmtime_r' function. */
|
||||
#undef HAVE_GMTIME_R
|
||||
|
||||
/* Define to 1 if you have the <grp.h> header file. */
|
||||
#undef HAVE_GRP_H
|
||||
|
||||
/* If you have HMAC_CTX_init */
|
||||
#undef HAVE_HMAC_CTX_INIT
|
||||
|
||||
/* Define to 1 if you have the `inet_aton' function. */
|
||||
#undef HAVE_INET_ATON
|
||||
|
||||
/* Define to 1 if you have the `inet_ntop' function. */
|
||||
#undef HAVE_INET_NTOP
|
||||
|
||||
/* Define to 1 if you have the `inet_pton' function. */
|
||||
#undef HAVE_INET_PTON
|
||||
|
||||
/* Define to 1 if you have the `initgroups' function. */
|
||||
#undef HAVE_INITGROUPS
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* if the function 'ioctlsocket' is available */
|
||||
#undef HAVE_IOCTLSOCKET
|
||||
|
||||
/* Define to 1 if you have the <iphlpapi.h> header file. */
|
||||
#undef HAVE_IPHLPAPI_H
|
||||
|
||||
/* Define to 1 if you have the `kill' function. */
|
||||
#undef HAVE_KILL
|
||||
|
||||
/* Define to 1 if you have the `ldns_key_EVP_unload_gost' function. */
|
||||
#undef HAVE_LDNS_KEY_EVP_UNLOAD_GOST
|
||||
|
||||
/* Define to 1 if you have the <ldns/ldns.h> header file. */
|
||||
#undef HAVE_LDNS_LDNS_H
|
||||
|
||||
/* Define to 1 if you have the `ldns' library (-lldns). */
|
||||
#undef HAVE_LIBLDNS
|
||||
|
||||
/* Define to 1 if you have the `localtime_r' function. */
|
||||
#undef HAVE_LOCALTIME_R
|
||||
|
||||
/* Define to 1 if you have the <login_cap.h> header file. */
|
||||
#undef HAVE_LOGIN_CAP_H
|
||||
|
||||
/* If have GNU libc compatible malloc */
|
||||
#undef HAVE_MALLOC
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if you have the `OPENSSL_config' function. */
|
||||
#undef HAVE_OPENSSL_CONFIG
|
||||
|
||||
/* Define to 1 if you have the <openssl/conf.h> header file. */
|
||||
#undef HAVE_OPENSSL_CONF_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/engine.h> header file. */
|
||||
#undef HAVE_OPENSSL_ENGINE_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/err.h> header file. */
|
||||
#undef HAVE_OPENSSL_ERR_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/rand.h> header file. */
|
||||
#undef HAVE_OPENSSL_RAND_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/ssl.h> header file. */
|
||||
#undef HAVE_OPENSSL_SSL_H
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#undef HAVE_PTHREAD
|
||||
|
||||
/* Define to 1 if the system has the type `pthread_rwlock_t'. */
|
||||
#undef HAVE_PTHREAD_RWLOCK_T
|
||||
|
||||
/* Define to 1 if the system has the type `pthread_spinlock_t'. */
|
||||
#undef HAVE_PTHREAD_SPINLOCK_T
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#undef HAVE_PWD_H
|
||||
|
||||
/* Define if you have Python libraries and header files. */
|
||||
#undef HAVE_PYTHON
|
||||
|
||||
/* Define to 1 if you have the `random' function. */
|
||||
#undef HAVE_RANDOM
|
||||
|
||||
/* Define to 1 if you have the `recvmsg' function. */
|
||||
#undef HAVE_RECVMSG
|
||||
|
||||
/* Define to 1 if you have the `sbrk' function. */
|
||||
#undef HAVE_SBRK
|
||||
|
||||
/* Define to 1 if you have the `sendmsg' function. */
|
||||
#undef HAVE_SENDMSG
|
||||
|
||||
/* Define to 1 if you have the `setregid' function. */
|
||||
#undef HAVE_SETREGID
|
||||
|
||||
/* Define to 1 if you have the `setresgid' function. */
|
||||
#undef HAVE_SETRESGID
|
||||
|
||||
/* Define to 1 if you have the `setresuid' function. */
|
||||
#undef HAVE_SETRESUID
|
||||
|
||||
/* Define to 1 if you have the `setreuid' function. */
|
||||
#undef HAVE_SETREUID
|
||||
|
||||
/* Define to 1 if you have the `setrlimit' function. */
|
||||
#undef HAVE_SETRLIMIT
|
||||
|
||||
/* Define to 1 if you have the `setsid' function. */
|
||||
#undef HAVE_SETSID
|
||||
|
||||
/* Define to 1 if you have the `setusercontext' function. */
|
||||
#undef HAVE_SETUSERCONTEXT
|
||||
|
||||
/* Define to 1 if you have the `sigprocmask' function. */
|
||||
#undef HAVE_SIGPROCMASK
|
||||
|
||||
/* Define to 1 if you have the `sleep' function. */
|
||||
#undef HAVE_SLEEP
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#undef HAVE_SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the `socketpair' function. */
|
||||
#undef HAVE_SOCKETPAIR
|
||||
|
||||
/* Using Solaris threads */
|
||||
#undef HAVE_SOLARIS_THREADS
|
||||
|
||||
/* Define to 1 if you have the `srandom' function. */
|
||||
#undef HAVE_SRANDOM
|
||||
|
||||
/* Define if you have the SSL libraries installed. */
|
||||
#undef HAVE_SSL
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#undef HAVE_STDARG_H
|
||||
|
||||
/* Define to 1 if you have the <stdbool.h> header file. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strftime' function. */
|
||||
#undef HAVE_STRFTIME
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strlcpy' function. */
|
||||
#undef HAVE_STRLCPY
|
||||
|
||||
/* Define to 1 if you have the `strptime' function. */
|
||||
#undef HAVE_STRPTIME
|
||||
|
||||
/* Define to 1 if `ipi_spec_dst' is a member of `struct in_pktinfo'. */
|
||||
#undef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
|
||||
|
||||
/* Define if you have Swig libraries and header files. */
|
||||
#undef HAVE_SWIG
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#undef HAVE_SYSLOG_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
#undef HAVE_SYS_RESOURCE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/uio.h> header file. */
|
||||
#undef HAVE_SYS_UIO_H
|
||||
|
||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#undef HAVE_TIME_H
|
||||
|
||||
/* Define to 1 if you have the `tzset' function. */
|
||||
#undef HAVE_TZSET
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the `usleep' function. */
|
||||
#undef HAVE_USLEEP
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#undef HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
#undef HAVE_VFORK_H
|
||||
|
||||
/* Define to 1 if you have the <windows.h> header file. */
|
||||
#undef HAVE_WINDOWS_H
|
||||
|
||||
/* Using Windows threads */
|
||||
#undef HAVE_WINDOWS_THREADS
|
||||
|
||||
/* Define to 1 if you have the <winsock2.h> header file. */
|
||||
#undef HAVE_WINSOCK2_H
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#undef HAVE_WORKING_FORK
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#undef HAVE_WORKING_VFORK
|
||||
|
||||
/* Define to 1 if you have the `writev' function. */
|
||||
#undef HAVE_WRITEV
|
||||
|
||||
/* Define to 1 if you have the <ws2tcpip.h> header file. */
|
||||
#undef HAVE_WS2TCPIP_H
|
||||
|
||||
/* Define to 1 if you have the `_beginthreadex' function. */
|
||||
#undef HAVE__BEGINTHREADEX
|
||||
|
||||
/* if lex has yylex_destroy */
|
||||
#undef LEX_HAS_YYLEX_DESTROY
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Define to the maximum message length to pass to syslog. */
|
||||
#undef MAXSYSLOGMSGLEN
|
||||
|
||||
/* Define if memcmp() does not compare unsigned bytes */
|
||||
#undef MEMCMP_IS_BROKEN
|
||||
|
||||
/* Define if mkdir has one argument. */
|
||||
#undef MKDIR_HAS_ONE_ARG
|
||||
|
||||
/* Define if the network stack does not fully support nonblocking io (causes
|
||||
lower performance). */
|
||||
#undef NONBLOCKING_IS_BROKEN
|
||||
|
||||
/* Put -D_ALL_SOURCE define in config.h */
|
||||
#undef OMITTED__D_ALL_SOURCE
|
||||
|
||||
/* Put -D_BSD_SOURCE define in config.h */
|
||||
#undef OMITTED__D_BSD_SOURCE
|
||||
|
||||
/* Put -D_GNU_SOURCE define in config.h */
|
||||
#undef OMITTED__D_GNU_SOURCE
|
||||
|
||||
/* Put -D_LARGEFILE_SOURCE=1 define in config.h */
|
||||
#undef OMITTED__D_LARGEFILE_SOURCE_1
|
||||
|
||||
/* Put -D_POSIX_C_SOURCE=200112 define in config.h */
|
||||
#undef OMITTED__D_POSIX_C_SOURCE_200112
|
||||
|
||||
/* Put -D_XOPEN_SOURCE=600 define in config.h */
|
||||
#undef OMITTED__D_XOPEN_SOURCE_600
|
||||
|
||||
/* Put -D_XOPEN_SOURCE_EXTENDED=1 define in config.h */
|
||||
#undef OMITTED__D_XOPEN_SOURCE_EXTENDED_1
|
||||
|
||||
/* Put -D__EXTENSIONS__ define in config.h */
|
||||
#undef OMITTED__D__EXTENSIONS__
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* default pidfile location */
|
||||
#undef PIDFILE
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
#undef PTHREAD_CREATE_JOINABLE
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* default rootkey location */
|
||||
#undef ROOT_ANCHOR_FILE
|
||||
|
||||
/* default rootcert location */
|
||||
#undef ROOT_CERT_FILE
|
||||
|
||||
/* version number for resource files */
|
||||
#undef RSRC_PACKAGE_VERSION
|
||||
|
||||
/* Directory to chdir to */
|
||||
#undef RUN_DIR
|
||||
|
||||
/* Shared data */
|
||||
#undef SHARE_DIR
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* use default strptime. */
|
||||
#undef STRPTIME_WORKS
|
||||
|
||||
/* Use win32 resources and API */
|
||||
#undef UB_ON_WINDOWS
|
||||
|
||||
/* default username */
|
||||
#undef UB_USERNAME
|
||||
|
||||
/* use to enable lightweight alloc assertions, for debug use */
|
||||
#undef UNBOUND_ALLOC_LITE
|
||||
|
||||
/* use malloc not regions, for debug use */
|
||||
#undef UNBOUND_ALLOC_NONREGIONAL
|
||||
|
||||
/* use statistics for allocs and frees, for debug use */
|
||||
#undef UNBOUND_ALLOC_STATS
|
||||
|
||||
/* define this to enable debug checks. */
|
||||
#undef UNBOUND_DEBUG
|
||||
|
||||
/* Define this to enable ECDSA support. */
|
||||
#undef USE_ECDSA
|
||||
|
||||
/* Define this to enable an EVP workaround for older openssl */
|
||||
#undef USE_ECDSA_EVP_WORKAROUND
|
||||
|
||||
/* Define this to enable GOST support. */
|
||||
#undef USE_GOST
|
||||
|
||||
/* Define if you want to use internal select based events */
|
||||
#undef USE_MINI_EVENT
|
||||
|
||||
/* Define this to enable SHA256 and SHA512 support. */
|
||||
#undef USE_SHA2
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Whether the windows socket API is used */
|
||||
#undef USE_WINSOCK
|
||||
|
||||
/* the version of the windows API enabled */
|
||||
#undef WINVER
|
||||
|
||||
/* Define if you want Python module. */
|
||||
#undef WITH_PYTHONMODULE
|
||||
|
||||
/* Define if you want PyUnbound. */
|
||||
#undef WITH_PYUNBOUND
|
||||
|
||||
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
||||
`char[]'. */
|
||||
#undef YYTEXT_POINTER
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
|
||||
#undef _LARGEFILE_SOURCE
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
#undef _POSIX_1_SOURCE
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef gid_t
|
||||
|
||||
/* in_addr_t */
|
||||
#undef in_addr_t
|
||||
|
||||
/* in_port_t */
|
||||
#undef in_port_t
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to `short' if <sys/types.h> does not define. */
|
||||
#undef int16_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef int32_t
|
||||
|
||||
/* Define to `long long' if <sys/types.h> does not define. */
|
||||
#undef int64_t
|
||||
|
||||
/* Define to `signed char' if <sys/types.h> does not define. */
|
||||
#undef int8_t
|
||||
|
||||
/* Define if replacement function should be used. */
|
||||
#undef malloc
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
#undef off_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to 'int' if not defined */
|
||||
#undef rlim_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to 'int' if not defined */
|
||||
#undef socklen_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define to 'unsigned char if not defined */
|
||||
#undef u_char
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef uid_t
|
||||
|
||||
/* Define to `unsigned short' if <sys/types.h> does not define. */
|
||||
#undef uint16_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef uint32_t
|
||||
|
||||
/* Define to `unsigned long long' if <sys/types.h> does not define. */
|
||||
#undef uint64_t
|
||||
|
||||
/* Define to `unsigned char' if <sys/types.h> does not define. */
|
||||
#undef uint8_t
|
||||
|
||||
/* Define as `fork' if `vfork' does not work. */
|
||||
#undef vfork
|
||||
|
||||
#if defined(OMITTED__D_GNU_SOURCE) && !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#if defined(OMITTED__D_BSD_SOURCE) && !defined(_BSD_SOURCE)
|
||||
#define _BSD_SOURCE 1
|
||||
#endif
|
||||
|
||||
#if defined(OMITTED__D__EXTENSIONS__) && !defined(__EXTENSIONS__)
|
||||
#define __EXTENSIONS__ 1
|
||||
#endif
|
||||
|
||||
#if defined(OMITTED__D_POSIX_C_SOURCE_200112) && !defined(_POSIX_C_SOURCE)
|
||||
#define _POSIX_C_SOURCE 200112
|
||||
#endif
|
||||
|
||||
#if defined(OMITTED__D_XOPEN_SOURCE_600) && !defined(_XOPEN_SOURCE)
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
|
||||
#if defined(OMITTED__D_XOPEN_SOURCE_EXTENDED_1) && !defined(_XOPEN_SOURCE_EXTENDED)
|
||||
#define _XOPEN_SOURCE_EXTENDED 1
|
||||
#endif
|
||||
|
||||
#if defined(OMITTED__D_ALL_SOURCE) && !defined(_ALL_SOURCE)
|
||||
#define _ALL_SOURCE 1
|
||||
#endif
|
||||
|
||||
#if defined(OMITTED__D_LARGEFILE_SOURCE_1) && !defined(_LARGEFILE_SOURCE)
|
||||
#define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef UNBOUND_DEBUG
|
||||
# define NDEBUG
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WS2TCPIP_H
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_ATTR_FORMAT
|
||||
# define ATTR_FORMAT(archetype, string_index, first_to_check) \
|
||||
__attribute__ ((format (archetype, string_index, first_to_check)))
|
||||
#else /* !HAVE_ATTR_FORMAT */
|
||||
# define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */
|
||||
#endif /* !HAVE_ATTR_FORMAT */
|
||||
|
||||
|
||||
#if defined(DOXYGEN)
|
||||
# define ATTR_UNUSED(x) x
|
||||
#elif defined(__cplusplus)
|
||||
# define ATTR_UNUSED(x)
|
||||
#elif defined(HAVE_ATTR_UNUSED)
|
||||
# define ATTR_UNUSED(x) x __attribute__((unused))
|
||||
#else /* !HAVE_ATTR_UNUSED */
|
||||
# define ATTR_UNUSED(x) x
|
||||
#endif /* !HAVE_ATTR_UNUSED */
|
||||
|
||||
|
||||
#ifndef HAVE_FSEEKO
|
||||
#define fseeko fseek
|
||||
#define ftello ftell
|
||||
#endif /* HAVE_FSEEKO */
|
||||
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN 256
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_SNPRINTF
|
||||
#define snprintf snprintf_unbound
|
||||
#define vsnprintf vsnprintf_unbound
|
||||
#include <stdarg.h>
|
||||
int snprintf (char *str, size_t count, const char *fmt, ...);
|
||||
int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
|
||||
#endif /* HAVE_SNPRINTF */
|
||||
|
||||
|
||||
#ifndef HAVE_INET_PTON
|
||||
#define inet_pton inet_pton_unbound
|
||||
int inet_pton(int af, const char* src, void* dst);
|
||||
#endif /* HAVE_INET_PTON */
|
||||
|
||||
|
||||
#ifndef HAVE_INET_NTOP
|
||||
#define inet_ntop inet_ntop_unbound
|
||||
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_INET_ATON
|
||||
#define inet_aton inet_aton_unbound
|
||||
int inet_aton(const char *cp, struct in_addr *addr);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_MEMMOVE
|
||||
#define memmove memmove_unbound
|
||||
void *memmove(void *dest, const void *src, size_t n);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
#define strlcpy strlcpy_unbound
|
||||
size_t strlcpy(char *dst, const char *src, size_t siz);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_GMTIME_R
|
||||
#define gmtime_r gmtime_r_unbound
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HAVE_SLEEP
|
||||
#define sleep(x) Sleep((x)*1000) /* on win32 */
|
||||
#endif /* HAVE_SLEEP */
|
||||
|
||||
|
||||
#ifndef HAVE_USLEEP
|
||||
#define usleep(x) Sleep((x)/1000 + 1) /* on win32 */
|
||||
#endif /* HAVE_USLEEP */
|
||||
|
||||
|
||||
#ifndef HAVE_RANDOM
|
||||
#define random rand /* on win32, for tests only (bad random) */
|
||||
#endif /* HAVE_RANDOM */
|
||||
|
||||
|
||||
#ifndef HAVE_SRANDOM
|
||||
#define srandom(x) srand(x) /* on win32, for tests only (bad random) */
|
||||
#endif /* HAVE_SRANDOM */
|
||||
|
||||
|
||||
/* detect if we need to cast to unsigned int for FD_SET to avoid warnings */
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
#define FD_SET_T (u_int)
|
||||
#else
|
||||
#define FD_SET_T
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef IPV6_MIN_MTU
|
||||
#define IPV6_MIN_MTU 1280
|
||||
#endif /* IPV6_MIN_MTU */
|
||||
|
||||
|
||||
#ifdef MEMCMP_IS_BROKEN
|
||||
#include "compat/memcmp.h"
|
||||
#define memcmp memcmp_unbound
|
||||
int memcmp(const void *x, const void *y, size_t n);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef HAVE_CTIME_R
|
||||
#define ctime_r unbound_ctime_r
|
||||
char *ctime_r(const time_t *timep, char *buf);
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_STRPTIME) || !defined(STRPTIME_WORKS)
|
||||
#define strptime unbound_strptime
|
||||
struct tm;
|
||||
char *strptime(const char *s, const char *format, struct tm *tm);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_EVENT_H) && !defined(HAVE_EVENT_BASE_ONCE) && !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) && (defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS))
|
||||
/* using version of libevent that is not threadsafe. */
|
||||
# define LIBEVENT_SIGNAL_PROBLEM 1
|
||||
#endif
|
||||
|
||||
#ifndef CHECKED_INET6
|
||||
# define CHECKED_INET6
|
||||
# ifdef AF_INET6
|
||||
# define INET6
|
||||
# else
|
||||
# define AF_INET6 28
|
||||
# endif
|
||||
#endif /* CHECKED_INET6 */
|
||||
|
||||
/* maximum nesting of included files */
|
||||
#define MAXINCLUDES 10
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
struct sockaddr_storage;
|
||||
#include "compat/fake-rfc2553.h"
|
||||
#endif
|
||||
|
||||
#ifdef UNBOUND_ALLOC_STATS
|
||||
# define malloc(s) unbound_stat_malloc_log(s, __FILE__, __LINE__, __func__)
|
||||
# define calloc(n,s) unbound_stat_calloc_log(n, s, __FILE__, __LINE__, __func__)
|
||||
# define free(p) unbound_stat_free_log(p, __FILE__, __LINE__, __func__)
|
||||
# define realloc(p,s) unbound_stat_realloc_log(p, s, __FILE__, __LINE__, __func__)
|
||||
void *unbound_stat_malloc(size_t size);
|
||||
void *unbound_stat_calloc(size_t nmemb, size_t size);
|
||||
void unbound_stat_free(void *ptr);
|
||||
void *unbound_stat_realloc(void *ptr, size_t size);
|
||||
void *unbound_stat_malloc_log(size_t size, const char* file, int line,
|
||||
const char* func);
|
||||
void *unbound_stat_calloc_log(size_t nmemb, size_t size, const char* file,
|
||||
int line, const char* func);
|
||||
void unbound_stat_free_log(void *ptr, const char* file, int line,
|
||||
const char* func);
|
||||
void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file,
|
||||
int line, const char* func);
|
||||
#elif defined(UNBOUND_ALLOC_LITE)
|
||||
# include "util/alloc.h"
|
||||
#endif /* UNBOUND_ALLOC_LITE and UNBOUND_ALLOC_STATS */
|
||||
|
||||
/** default port for DNS traffic. */
|
||||
#define UNBOUND_DNS_PORT 53
|
||||
/** default port for unbound control traffic, registered port with IANA,
|
||||
ub-dns-control 8953/tcp unbound dns nameserver control */
|
||||
#define UNBOUND_CONTROL_PORT 8953
|
||||
/** the version of unbound-control that this software implements */
|
||||
#define UNBOUND_CONTROL_VERSION 1
|
||||
|
||||
|
1705
contrib/unbound/config.sub
vendored
Executable file
1705
contrib/unbound/config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
20265
contrib/unbound/configure
vendored
Executable file
20265
contrib/unbound/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1197
contrib/unbound/configure.ac
Normal file
1197
contrib/unbound/configure.ac
Normal file
File diff suppressed because it is too large
Load Diff
176
contrib/unbound/daemon/acl_list.c
Normal file
176
contrib/unbound/daemon/acl_list.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* daemon/acl_list.h - client access control storage for the server.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file helps the server keep out queries from outside sources, that
|
||||
* should not be answered.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "daemon/acl_list.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
|
||||
struct acl_list*
|
||||
acl_list_create(void)
|
||||
{
|
||||
struct acl_list* acl = (struct acl_list*)calloc(1,
|
||||
sizeof(struct acl_list));
|
||||
if(!acl)
|
||||
return NULL;
|
||||
acl->region = regional_create();
|
||||
if(!acl->region) {
|
||||
acl_list_delete(acl);
|
||||
return NULL;
|
||||
}
|
||||
return acl;
|
||||
}
|
||||
|
||||
void
|
||||
acl_list_delete(struct acl_list* acl)
|
||||
{
|
||||
if(!acl)
|
||||
return;
|
||||
regional_destroy(acl->region);
|
||||
free(acl);
|
||||
}
|
||||
|
||||
/** insert new address into acl_list structure */
|
||||
static int
|
||||
acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int net, enum acl_access control,
|
||||
int complain_duplicates)
|
||||
{
|
||||
struct acl_addr* node = regional_alloc(acl->region,
|
||||
sizeof(struct acl_addr));
|
||||
if(!node)
|
||||
return 0;
|
||||
node->control = control;
|
||||
if(!addr_tree_insert(&acl->tree, &node->node, addr, addrlen, net)) {
|
||||
if(complain_duplicates)
|
||||
verbose(VERB_QUERY, "duplicate acl address ignored.");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** apply acl_list string */
|
||||
static int
|
||||
acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
|
||||
int complain_duplicates)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
socklen_t addrlen;
|
||||
enum acl_access control;
|
||||
if(strcmp(s2, "allow") == 0)
|
||||
control = acl_allow;
|
||||
else if(strcmp(s2, "deny") == 0)
|
||||
control = acl_deny;
|
||||
else if(strcmp(s2, "refuse") == 0)
|
||||
control = acl_refuse;
|
||||
else if(strcmp(s2, "allow_snoop") == 0)
|
||||
control = acl_allow_snoop;
|
||||
else {
|
||||
log_err("access control type %s unknown", str);
|
||||
return 0;
|
||||
}
|
||||
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
|
||||
log_err("cannot parse access control: %s %s", str, s2);
|
||||
return 0;
|
||||
}
|
||||
if(!acl_list_insert(acl, &addr, addrlen, net, control,
|
||||
complain_duplicates)) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** read acl_list config */
|
||||
static int
|
||||
read_acl_list(struct acl_list* acl, struct config_file* cfg)
|
||||
{
|
||||
struct config_str2list* p;
|
||||
for(p = cfg->acls; p; p = p->next) {
|
||||
log_assert(p->str && p->str2);
|
||||
if(!acl_list_str_cfg(acl, p->str, p->str2, 1))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg)
|
||||
{
|
||||
regional_free_all(acl->region);
|
||||
addr_tree_init(&acl->tree);
|
||||
if(!read_acl_list(acl, cfg))
|
||||
return 0;
|
||||
/* insert defaults, with '0' to ignore them if they are duplicates */
|
||||
if(!acl_list_str_cfg(acl, "0.0.0.0/0", "refuse", 0))
|
||||
return 0;
|
||||
if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
|
||||
return 0;
|
||||
if(cfg->do_ip6) {
|
||||
if(!acl_list_str_cfg(acl, "::0/0", "refuse", 0))
|
||||
return 0;
|
||||
if(!acl_list_str_cfg(acl, "::1", "allow", 0))
|
||||
return 0;
|
||||
if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0))
|
||||
return 0;
|
||||
}
|
||||
addr_tree_init_parents(&acl->tree);
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum acl_access
|
||||
acl_list_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
struct acl_addr* r = (struct acl_addr*)addr_tree_lookup(&acl->tree,
|
||||
addr, addrlen);
|
||||
if(r) return r->control;
|
||||
return acl_deny;
|
||||
}
|
||||
|
||||
size_t
|
||||
acl_list_get_mem(struct acl_list* acl)
|
||||
{
|
||||
if(!acl) return 0;
|
||||
return sizeof(*acl) + regional_get_mem(acl->region);
|
||||
}
|
125
contrib/unbound/daemon/acl_list.h
Normal file
125
contrib/unbound/daemon/acl_list.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* daemon/acl_list.h - client access control storage for the server.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file keeps track of the list of clients that are allowed to
|
||||
* access the server.
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_ACL_LIST_H
|
||||
#define DAEMON_ACL_LIST_H
|
||||
#include "util/storage/dnstree.h"
|
||||
struct config_file;
|
||||
struct regional;
|
||||
|
||||
/**
|
||||
* Enumeration of access control options for an address range.
|
||||
* Allow or deny access.
|
||||
*/
|
||||
enum acl_access {
|
||||
/** disallow any access whatsoever, drop it */
|
||||
acl_deny = 0,
|
||||
/** disallow access, send a polite 'REFUSED' reply */
|
||||
acl_refuse,
|
||||
/** allow full access for recursion (+RD) queries */
|
||||
acl_allow,
|
||||
/** allow full access for all queries, recursion and cache snooping */
|
||||
acl_allow_snoop
|
||||
};
|
||||
|
||||
/**
|
||||
* Access control storage structure
|
||||
*/
|
||||
struct acl_list {
|
||||
/** regional for allocation */
|
||||
struct regional* region;
|
||||
/**
|
||||
* Tree of the addresses that are allowed/blocked.
|
||||
* contents of type acl_addr.
|
||||
*/
|
||||
rbtree_t tree;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* An address span with access control information
|
||||
*/
|
||||
struct acl_addr {
|
||||
/** node in address tree */
|
||||
struct addr_tree_node node;
|
||||
/** access control on this netblock */
|
||||
enum acl_access control;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create acl structure
|
||||
* @return new structure or NULL on error.
|
||||
*/
|
||||
struct acl_list* acl_list_create(void);
|
||||
|
||||
/**
|
||||
* Delete acl structure.
|
||||
* @param acl: to delete.
|
||||
*/
|
||||
void acl_list_delete(struct acl_list* acl);
|
||||
|
||||
/**
|
||||
* Process access control config.
|
||||
* @param acl: where to store.
|
||||
* @param cfg: config options.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Lookup address to see its access control status.
|
||||
* @param acl: structure for address storage.
|
||||
* @param addr: address to check
|
||||
* @param addrlen: length of addr.
|
||||
* @return: what to do with message from this address.
|
||||
*/
|
||||
enum acl_access acl_list_lookup(struct acl_list* acl,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Get memory used by acl structure.
|
||||
* @param acl: structure for address storage.
|
||||
* @return bytes in use.
|
||||
*/
|
||||
size_t acl_list_get_mem(struct acl_list* acl);
|
||||
|
||||
#endif /* DAEMON_ACL_LIST_H */
|
986
contrib/unbound/daemon/cachedump.c
Normal file
986
contrib/unbound/daemon/cachedump.c
Normal file
@ -0,0 +1,986 @@
|
||||
/*
|
||||
* daemon/cachedump.c - dump the cache to text format.
|
||||
*
|
||||
* Copyright (c) 2008, 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
|
||||
*
|
||||
* This file contains functions to read and write the cache(s)
|
||||
* to text format.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <ldns/ldns.h>
|
||||
#include "daemon/cachedump.h"
|
||||
#include "daemon/remote.h"
|
||||
#include "daemon/worker.h"
|
||||
#include "daemon/daemon.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/modstack.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "iterator/iterator.h"
|
||||
#include "iterator/iter_delegpt.h"
|
||||
#include "iterator/iter_utils.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
|
||||
/** convert to ldns rr */
|
||||
static ldns_rr*
|
||||
to_rr(struct ub_packed_rrset_key* k, struct packed_rrset_data* d,
|
||||
uint32_t now, size_t i, uint16_t type)
|
||||
{
|
||||
ldns_rr* rr = ldns_rr_new();
|
||||
ldns_rdf* rdf;
|
||||
ldns_status status;
|
||||
size_t pos;
|
||||
log_assert(i < d->count + d->rrsig_count);
|
||||
if(!rr) {
|
||||
return NULL;
|
||||
}
|
||||
ldns_rr_set_type(rr, type);
|
||||
ldns_rr_set_class(rr, ntohs(k->rk.rrset_class));
|
||||
if(d->rr_ttl[i] < now)
|
||||
ldns_rr_set_ttl(rr, 0);
|
||||
else ldns_rr_set_ttl(rr, d->rr_ttl[i] - now);
|
||||
pos = 0;
|
||||
status = ldns_wire2dname(&rdf, k->rk.dname, k->rk.dname_len, &pos);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
/* we drop detailed error in status */
|
||||
ldns_rr_free(rr);
|
||||
return NULL;
|
||||
}
|
||||
ldns_rr_set_owner(rr, rdf);
|
||||
pos = 0;
|
||||
status = ldns_wire2rdf(rr, d->rr_data[i], d->rr_len[i], &pos);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
/* we drop detailed error in status */
|
||||
ldns_rr_free(rr);
|
||||
return NULL;
|
||||
}
|
||||
return rr;
|
||||
}
|
||||
|
||||
/** dump one rrset zonefile line */
|
||||
static int
|
||||
dump_rrset_line(SSL* ssl, struct ub_packed_rrset_key* k,
|
||||
struct packed_rrset_data* d, uint32_t now, size_t i, uint16_t type)
|
||||
{
|
||||
char* s;
|
||||
ldns_rr* rr = to_rr(k, d, now, i, type);
|
||||
if(!rr) {
|
||||
return ssl_printf(ssl, "BADRR\n");
|
||||
}
|
||||
s = ldns_rr2str(rr);
|
||||
ldns_rr_free(rr);
|
||||
if(!s) {
|
||||
return ssl_printf(ssl, "BADRR\n");
|
||||
}
|
||||
if(!ssl_printf(ssl, "%s", s)) {
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
free(s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump rrset key and data info */
|
||||
static int
|
||||
dump_rrset(SSL* ssl, struct ub_packed_rrset_key* k,
|
||||
struct packed_rrset_data* d, uint32_t now)
|
||||
{
|
||||
size_t i;
|
||||
/* rd lock held by caller */
|
||||
if(!k || !d) return 1;
|
||||
if(d->ttl < now) return 1; /* expired */
|
||||
|
||||
/* meta line */
|
||||
if(!ssl_printf(ssl, ";rrset%s %u %u %u %d %d\n",
|
||||
(k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"",
|
||||
(unsigned)(d->ttl - now),
|
||||
(unsigned)d->count, (unsigned)d->rrsig_count,
|
||||
(int)d->trust, (int)d->security
|
||||
))
|
||||
return 0;
|
||||
for(i=0; i<d->count; i++) {
|
||||
if(!dump_rrset_line(ssl, k, d, now, i, ntohs(k->rk.type)))
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<d->rrsig_count; i++) {
|
||||
if(!dump_rrset_line(ssl, k, d, now, i+d->count,
|
||||
LDNS_RR_TYPE_RRSIG))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump lruhash rrset cache */
|
||||
static int
|
||||
dump_rrset_lruhash(SSL* ssl, struct lruhash* h, uint32_t now)
|
||||
{
|
||||
struct lruhash_entry* e;
|
||||
/* lruhash already locked by caller */
|
||||
/* walk in order of lru; best first */
|
||||
for(e=h->lru_start; e; e = e->lru_next) {
|
||||
lock_rw_rdlock(&e->lock);
|
||||
if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key,
|
||||
(struct packed_rrset_data*)e->data, now)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump rrset cache */
|
||||
static int
|
||||
dump_rrset_cache(SSL* ssl, struct worker* worker)
|
||||
{
|
||||
struct rrset_cache* r = worker->env.rrset_cache;
|
||||
size_t slab;
|
||||
if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0;
|
||||
for(slab=0; slab<r->table.size; slab++) {
|
||||
lock_quick_lock(&r->table.array[slab]->lock);
|
||||
if(!dump_rrset_lruhash(ssl, r->table.array[slab],
|
||||
*worker->env.now)) {
|
||||
lock_quick_unlock(&r->table.array[slab]->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_quick_unlock(&r->table.array[slab]->lock);
|
||||
}
|
||||
return ssl_printf(ssl, "END_RRSET_CACHE\n");
|
||||
}
|
||||
|
||||
/** dump message to rrset reference */
|
||||
static int
|
||||
dump_msg_ref(SSL* ssl, struct ub_packed_rrset_key* k)
|
||||
{
|
||||
ldns_rdf* rdf;
|
||||
ldns_status status;
|
||||
size_t pos;
|
||||
char* nm, *tp, *cl;
|
||||
|
||||
pos = 0;
|
||||
status = ldns_wire2dname(&rdf, k->rk.dname, k->rk.dname_len, &pos);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
return ssl_printf(ssl, "BADREF\n");
|
||||
}
|
||||
nm = ldns_rdf2str(rdf);
|
||||
ldns_rdf_deep_free(rdf);
|
||||
tp = ldns_rr_type2str(ntohs(k->rk.type));
|
||||
cl = ldns_rr_class2str(ntohs(k->rk.rrset_class));
|
||||
if(!nm || !cl || !tp) {
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return ssl_printf(ssl, "BADREF\n");
|
||||
}
|
||||
if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) {
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return 0;
|
||||
}
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump message entry */
|
||||
static int
|
||||
dump_msg(SSL* ssl, struct query_info* k, struct reply_info* d,
|
||||
uint32_t now)
|
||||
{
|
||||
size_t i;
|
||||
char* nm, *tp, *cl;
|
||||
ldns_rdf* rdf;
|
||||
ldns_status status;
|
||||
size_t pos;
|
||||
if(!k || !d) return 1;
|
||||
if(d->ttl < now) return 1; /* expired */
|
||||
|
||||
pos = 0;
|
||||
status = ldns_wire2dname(&rdf, k->qname, k->qname_len, &pos);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
return 1; /* skip this entry */
|
||||
}
|
||||
nm = ldns_rdf2str(rdf);
|
||||
ldns_rdf_deep_free(rdf);
|
||||
tp = ldns_rr_type2str(k->qtype);
|
||||
cl = ldns_rr_class2str(k->qclass);
|
||||
if(!nm || !tp || !cl) {
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return 1; /* skip this entry */
|
||||
}
|
||||
if(!rrset_array_lock(d->ref, d->rrset_count, now)) {
|
||||
/* rrsets have timed out or do not exist */
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return 1; /* skip this entry */
|
||||
}
|
||||
|
||||
/* meta line */
|
||||
if(!ssl_printf(ssl, "msg %s %s %s %d %d %u %d %u %u %u\n",
|
||||
nm, cl, tp,
|
||||
(int)d->flags, (int)d->qdcount,
|
||||
(unsigned)(d->ttl-now), (int)d->security,
|
||||
(unsigned)d->an_numrrsets,
|
||||
(unsigned)d->ns_numrrsets,
|
||||
(unsigned)d->ar_numrrsets)) {
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
return 0;
|
||||
}
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
|
||||
for(i=0; i<d->rrset_count; i++) {
|
||||
if(!dump_msg_ref(ssl, d->rrsets[i])) {
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** copy msg to worker pad */
|
||||
static int
|
||||
copy_msg(struct regional* region, struct lruhash_entry* e,
|
||||
struct query_info** k, struct reply_info** d)
|
||||
{
|
||||
struct reply_info* rep = (struct reply_info*)e->data;
|
||||
*d = (struct reply_info*)regional_alloc_init(region, e->data,
|
||||
sizeof(struct reply_info) +
|
||||
sizeof(struct rrset_ref) * (rep->rrset_count-1) +
|
||||
sizeof(struct ub_packed_rrset_key*) * rep->rrset_count);
|
||||
if(!*d)
|
||||
return 0;
|
||||
(*d)->rrsets = (struct ub_packed_rrset_key**)(
|
||||
(uint8_t*)(&((*d)->ref[0])) +
|
||||
sizeof(struct rrset_ref) * rep->rrset_count);
|
||||
*k = (struct query_info*)regional_alloc_init(region,
|
||||
e->key, sizeof(struct query_info));
|
||||
if(!*k)
|
||||
return 0;
|
||||
(*k)->qname = regional_alloc_init(region,
|
||||
(*k)->qname, (*k)->qname_len);
|
||||
return (*k)->qname != NULL;
|
||||
}
|
||||
|
||||
/** dump lruhash msg cache */
|
||||
static int
|
||||
dump_msg_lruhash(SSL* ssl, struct worker* worker, struct lruhash* h)
|
||||
{
|
||||
struct lruhash_entry* e;
|
||||
struct query_info* k;
|
||||
struct reply_info* d;
|
||||
|
||||
/* lruhash already locked by caller */
|
||||
/* walk in order of lru; best first */
|
||||
for(e=h->lru_start; e; e = e->lru_next) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
lock_rw_rdlock(&e->lock);
|
||||
/* make copy of rrset in worker buffer */
|
||||
if(!copy_msg(worker->scratchpad, e, &k, &d)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
/* release lock so we can lookup the rrset references
|
||||
* in the rrset cache */
|
||||
if(!dump_msg(ssl, k, d, *worker->env.now)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump msg cache */
|
||||
static int
|
||||
dump_msg_cache(SSL* ssl, struct worker* worker)
|
||||
{
|
||||
struct slabhash* sh = worker->env.msg_cache;
|
||||
size_t slab;
|
||||
if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0;
|
||||
for(slab=0; slab<sh->size; slab++) {
|
||||
lock_quick_lock(&sh->array[slab]->lock);
|
||||
if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) {
|
||||
lock_quick_unlock(&sh->array[slab]->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_quick_unlock(&sh->array[slab]->lock);
|
||||
}
|
||||
return ssl_printf(ssl, "END_MSG_CACHE\n");
|
||||
}
|
||||
|
||||
int
|
||||
dump_cache(SSL* ssl, struct worker* worker)
|
||||
{
|
||||
if(!dump_rrset_cache(ssl, worker))
|
||||
return 0;
|
||||
if(!dump_msg_cache(ssl, worker))
|
||||
return 0;
|
||||
return ssl_printf(ssl, "EOF\n");
|
||||
}
|
||||
|
||||
/** read a line from ssl into buffer */
|
||||
static int
|
||||
ssl_read_buf(SSL* ssl, ldns_buffer* buf)
|
||||
{
|
||||
return ssl_read_line(ssl, (char*)ldns_buffer_begin(buf),
|
||||
ldns_buffer_capacity(buf));
|
||||
}
|
||||
|
||||
/** check fixed text on line */
|
||||
static int
|
||||
read_fixed(SSL* ssl, ldns_buffer* buf, const char* str)
|
||||
{
|
||||
if(!ssl_read_buf(ssl, buf)) return 0;
|
||||
return (strcmp((char*)ldns_buffer_begin(buf), str) == 0);
|
||||
}
|
||||
|
||||
/** load an RR into rrset */
|
||||
static int
|
||||
load_rr(SSL* ssl, ldns_buffer* buf, struct regional* region,
|
||||
struct ub_packed_rrset_key* rk, struct packed_rrset_data* d,
|
||||
unsigned int i, int is_rrsig, int* go_on, uint32_t now)
|
||||
{
|
||||
ldns_rr* rr;
|
||||
ldns_status status;
|
||||
|
||||
/* read the line */
|
||||
if(!ssl_read_buf(ssl, buf))
|
||||
return 0;
|
||||
if(strncmp((char*)ldns_buffer_begin(buf), "BADRR\n", 6) == 0) {
|
||||
*go_on = 0;
|
||||
return 1;
|
||||
}
|
||||
status = ldns_rr_new_frm_str(&rr, (char*)ldns_buffer_begin(buf),
|
||||
LDNS_DEFAULT_TTL, NULL, NULL);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_warn("error cannot parse rr: %s: %s",
|
||||
ldns_get_errorstr_by_id(status),
|
||||
(char*)ldns_buffer_begin(buf));
|
||||
return 0;
|
||||
}
|
||||
if(is_rrsig && ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
|
||||
log_warn("error expected rrsig but got %s",
|
||||
(char*)ldns_buffer_begin(buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* convert ldns rr into packed_rr */
|
||||
d->rr_ttl[i] = ldns_rr_ttl(rr) + now;
|
||||
ldns_buffer_clear(buf);
|
||||
ldns_buffer_skip(buf, 2);
|
||||
status = ldns_rr_rdata2buffer_wire(buf, rr);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_warn("error cannot rr2wire: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
ldns_rr_free(rr);
|
||||
return 0;
|
||||
}
|
||||
ldns_buffer_flip(buf);
|
||||
ldns_buffer_write_u16_at(buf, 0, ldns_buffer_limit(buf) - 2);
|
||||
|
||||
d->rr_len[i] = ldns_buffer_limit(buf);
|
||||
d->rr_data[i] = (uint8_t*)regional_alloc_init(region,
|
||||
ldns_buffer_begin(buf), ldns_buffer_limit(buf));
|
||||
if(!d->rr_data[i]) {
|
||||
ldns_rr_free(rr);
|
||||
log_warn("error out of memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if first entry, fill the key structure */
|
||||
if(i==0) {
|
||||
rk->rk.type = htons(ldns_rr_get_type(rr));
|
||||
rk->rk.rrset_class = htons(ldns_rr_get_class(rr));
|
||||
ldns_buffer_clear(buf);
|
||||
status = ldns_dname2buffer_wire(buf, ldns_rr_owner(rr));
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_warn("error cannot dname2buffer: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
ldns_rr_free(rr);
|
||||
return 0;
|
||||
}
|
||||
ldns_buffer_flip(buf);
|
||||
rk->rk.dname_len = ldns_buffer_limit(buf);
|
||||
rk->rk.dname = regional_alloc_init(region,
|
||||
ldns_buffer_begin(buf), ldns_buffer_limit(buf));
|
||||
if(!rk->rk.dname) {
|
||||
log_warn("error out of memory");
|
||||
ldns_rr_free(rr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ldns_rr_free(rr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** move entry into cache */
|
||||
static int
|
||||
move_into_cache(struct ub_packed_rrset_key* k,
|
||||
struct packed_rrset_data* d, struct worker* worker)
|
||||
{
|
||||
struct ub_packed_rrset_key* ak;
|
||||
struct packed_rrset_data* ad;
|
||||
size_t s, i, num = d->count + d->rrsig_count;
|
||||
struct rrset_ref ref;
|
||||
uint8_t* p;
|
||||
|
||||
ak = alloc_special_obtain(&worker->alloc);
|
||||
if(!ak) {
|
||||
log_warn("error out of memory");
|
||||
return 0;
|
||||
}
|
||||
ak->entry.data = NULL;
|
||||
ak->rk = k->rk;
|
||||
ak->entry.hash = rrset_key_hash(&k->rk);
|
||||
ak->rk.dname = (uint8_t*)memdup(k->rk.dname, k->rk.dname_len);
|
||||
if(!ak->rk.dname) {
|
||||
log_warn("error out of memory");
|
||||
ub_packed_rrset_parsedelete(ak, &worker->alloc);
|
||||
return 0;
|
||||
}
|
||||
s = sizeof(*ad) + (sizeof(size_t) + sizeof(uint8_t*) +
|
||||
sizeof(uint32_t))* num;
|
||||
for(i=0; i<num; i++)
|
||||
s += d->rr_len[i];
|
||||
ad = (struct packed_rrset_data*)malloc(s);
|
||||
if(!ad) {
|
||||
log_warn("error out of memory");
|
||||
ub_packed_rrset_parsedelete(ak, &worker->alloc);
|
||||
return 0;
|
||||
}
|
||||
p = (uint8_t*)ad;
|
||||
memmove(p, d, sizeof(*ad));
|
||||
p += sizeof(*ad);
|
||||
memmove(p, &d->rr_len[0], sizeof(size_t)*num);
|
||||
p += sizeof(size_t)*num;
|
||||
memmove(p, &d->rr_data[0], sizeof(uint8_t*)*num);
|
||||
p += sizeof(uint8_t*)*num;
|
||||
memmove(p, &d->rr_ttl[0], sizeof(uint32_t)*num);
|
||||
p += sizeof(uint32_t)*num;
|
||||
for(i=0; i<num; i++) {
|
||||
memmove(p, d->rr_data[i], d->rr_len[i]);
|
||||
p += d->rr_len[i];
|
||||
}
|
||||
packed_rrset_ptr_fixup(ad);
|
||||
|
||||
ak->entry.data = ad;
|
||||
|
||||
ref.key = ak;
|
||||
ref.id = ak->id;
|
||||
(void)rrset_cache_update(worker->env.rrset_cache, &ref,
|
||||
&worker->alloc, *worker->env.now);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** load an rrset entry */
|
||||
static int
|
||||
load_rrset(SSL* ssl, ldns_buffer* buf, struct worker* worker)
|
||||
{
|
||||
char* s = (char*)ldns_buffer_begin(buf);
|
||||
struct regional* region = worker->scratchpad;
|
||||
struct ub_packed_rrset_key* rk;
|
||||
struct packed_rrset_data* d;
|
||||
unsigned int ttl, rr_count, rrsig_count, trust, security;
|
||||
unsigned int i;
|
||||
int go_on = 1;
|
||||
regional_free_all(region);
|
||||
|
||||
rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region,
|
||||
sizeof(*rk));
|
||||
d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d));
|
||||
if(!rk || !d) {
|
||||
log_warn("error out of memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(strncmp(s, ";rrset", 6) != 0) {
|
||||
log_warn("error expected ';rrset' but got %s", s);
|
||||
return 0;
|
||||
}
|
||||
s += 6;
|
||||
if(strncmp(s, " nsec_apex", 10) == 0) {
|
||||
s += 10;
|
||||
rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX;
|
||||
}
|
||||
if(sscanf(s, " %u %u %u %u %u", &ttl, &rr_count, &rrsig_count,
|
||||
&trust, &security) != 5) {
|
||||
log_warn("error bad rrset spec %s", s);
|
||||
return 0;
|
||||
}
|
||||
if(rr_count == 0 && rrsig_count == 0) {
|
||||
log_warn("bad rrset without contents");
|
||||
return 0;
|
||||
}
|
||||
d->count = (size_t)rr_count;
|
||||
d->rrsig_count = (size_t)rrsig_count;
|
||||
d->security = (enum sec_status)security;
|
||||
d->trust = (enum rrset_trust)trust;
|
||||
d->ttl = (uint32_t)ttl + *worker->env.now;
|
||||
|
||||
d->rr_len = regional_alloc_zero(region,
|
||||
sizeof(size_t)*(d->count+d->rrsig_count));
|
||||
d->rr_ttl = regional_alloc_zero(region,
|
||||
sizeof(uint32_t)*(d->count+d->rrsig_count));
|
||||
d->rr_data = regional_alloc_zero(region,
|
||||
sizeof(uint8_t*)*(d->count+d->rrsig_count));
|
||||
if(!d->rr_len || !d->rr_ttl || !d->rr_data) {
|
||||
log_warn("error out of memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read the rr's themselves */
|
||||
for(i=0; i<rr_count; i++) {
|
||||
if(!load_rr(ssl, buf, region, rk, d, i, 0,
|
||||
&go_on, *worker->env.now)) {
|
||||
log_warn("could not read rr %u", i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for(i=0; i<rrsig_count; i++) {
|
||||
if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1,
|
||||
&go_on, *worker->env.now)) {
|
||||
log_warn("could not read rrsig %u", i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(!go_on) {
|
||||
/* skip this entry */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return move_into_cache(rk, d, worker);
|
||||
}
|
||||
|
||||
/** load rrset cache */
|
||||
static int
|
||||
load_rrset_cache(SSL* ssl, struct worker* worker)
|
||||
{
|
||||
ldns_buffer* buf = worker->env.scratch_buffer;
|
||||
if(!read_fixed(ssl, buf, "START_RRSET_CACHE")) return 0;
|
||||
while(ssl_read_buf(ssl, buf) &&
|
||||
strcmp((char*)ldns_buffer_begin(buf), "END_RRSET_CACHE")!=0) {
|
||||
if(!load_rrset(ssl, buf, worker))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** read qinfo from next three words */
|
||||
static char*
|
||||
load_qinfo(char* str, struct query_info* qinfo, ldns_buffer* buf,
|
||||
struct regional* region)
|
||||
{
|
||||
/* s is part of the buf */
|
||||
char* s = str;
|
||||
ldns_rr* rr;
|
||||
ldns_status status;
|
||||
|
||||
/* skip three words */
|
||||
s = strchr(str, ' ');
|
||||
if(s) s = strchr(s+1, ' ');
|
||||
if(s) s = strchr(s+1, ' ');
|
||||
if(!s) {
|
||||
log_warn("error line too short, %s", str);
|
||||
return NULL;
|
||||
}
|
||||
s[0] = 0;
|
||||
s++;
|
||||
|
||||
/* parse them */
|
||||
status = ldns_rr_new_question_frm_str(&rr, str, NULL, NULL);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_warn("error cannot parse: %s %s",
|
||||
ldns_get_errorstr_by_id(status), str);
|
||||
return NULL;
|
||||
}
|
||||
qinfo->qtype = ldns_rr_get_type(rr);
|
||||
qinfo->qclass = ldns_rr_get_class(rr);
|
||||
ldns_buffer_clear(buf);
|
||||
status = ldns_dname2buffer_wire(buf, ldns_rr_owner(rr));
|
||||
ldns_rr_free(rr);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_warn("error cannot dname2wire: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
return NULL;
|
||||
}
|
||||
ldns_buffer_flip(buf);
|
||||
qinfo->qname_len = ldns_buffer_limit(buf);
|
||||
qinfo->qname = (uint8_t*)regional_alloc_init(region,
|
||||
ldns_buffer_begin(buf), ldns_buffer_limit(buf));
|
||||
if(!qinfo->qname) {
|
||||
log_warn("error out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/** load a msg rrset reference */
|
||||
static int
|
||||
load_ref(SSL* ssl, ldns_buffer* buf, struct worker* worker,
|
||||
struct regional *region, struct ub_packed_rrset_key** rrset,
|
||||
int* go_on)
|
||||
{
|
||||
char* s = (char*)ldns_buffer_begin(buf);
|
||||
struct query_info qinfo;
|
||||
unsigned int flags;
|
||||
struct ub_packed_rrset_key* k;
|
||||
|
||||
/* read line */
|
||||
if(!ssl_read_buf(ssl, buf))
|
||||
return 0;
|
||||
if(strncmp(s, "BADREF", 6) == 0) {
|
||||
*go_on = 0; /* its bad, skip it and skip message */
|
||||
return 1;
|
||||
}
|
||||
|
||||
s = load_qinfo(s, &qinfo, buf, region);
|
||||
if(!s) {
|
||||
return 0;
|
||||
}
|
||||
if(sscanf(s, " %u", &flags) != 1) {
|
||||
log_warn("error cannot parse flags: %s", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* lookup in cache */
|
||||
k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname,
|
||||
qinfo.qname_len, qinfo.qtype, qinfo.qclass,
|
||||
(uint32_t)flags, *worker->env.now, 0);
|
||||
if(!k) {
|
||||
/* not found or expired */
|
||||
*go_on = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* store in result */
|
||||
*rrset = packed_rrset_copy_region(k, region, *worker->env.now);
|
||||
lock_rw_unlock(&k->entry.lock);
|
||||
|
||||
return (*rrset != NULL);
|
||||
}
|
||||
|
||||
/** load a msg entry */
|
||||
static int
|
||||
load_msg(SSL* ssl, ldns_buffer* buf, struct worker* worker)
|
||||
{
|
||||
struct regional* region = worker->scratchpad;
|
||||
struct query_info qinf;
|
||||
struct reply_info rep;
|
||||
char* s = (char*)ldns_buffer_begin(buf);
|
||||
unsigned int flags, qdcount, ttl, security, an, ns, ar;
|
||||
size_t i;
|
||||
int go_on = 1;
|
||||
|
||||
regional_free_all(region);
|
||||
|
||||
if(strncmp(s, "msg ", 4) != 0) {
|
||||
log_warn("error expected msg but got %s", s);
|
||||
return 0;
|
||||
}
|
||||
s += 4;
|
||||
s = load_qinfo(s, &qinf, buf, region);
|
||||
if(!s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read remainder of line */
|
||||
if(sscanf(s, " %u %u %u %u %u %u %u", &flags, &qdcount, &ttl,
|
||||
&security, &an, &ns, &ar) != 7) {
|
||||
log_warn("error cannot parse numbers: %s", s);
|
||||
return 0;
|
||||
}
|
||||
rep.flags = (uint16_t)flags;
|
||||
rep.qdcount = (uint16_t)qdcount;
|
||||
rep.ttl = (uint32_t)ttl;
|
||||
rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl);
|
||||
rep.security = (enum sec_status)security;
|
||||
rep.an_numrrsets = (size_t)an;
|
||||
rep.ns_numrrsets = (size_t)ns;
|
||||
rep.ar_numrrsets = (size_t)ar;
|
||||
rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar;
|
||||
rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero(
|
||||
region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count);
|
||||
|
||||
/* fill repinfo with references */
|
||||
for(i=0; i<rep.rrset_count; i++) {
|
||||
if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i],
|
||||
&go_on)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!go_on)
|
||||
return 1; /* skip this one, not all references satisfied */
|
||||
|
||||
if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL)) {
|
||||
log_warn("error out of memory");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** load msg cache */
|
||||
static int
|
||||
load_msg_cache(SSL* ssl, struct worker* worker)
|
||||
{
|
||||
ldns_buffer* buf = worker->env.scratch_buffer;
|
||||
if(!read_fixed(ssl, buf, "START_MSG_CACHE")) return 0;
|
||||
while(ssl_read_buf(ssl, buf) &&
|
||||
strcmp((char*)ldns_buffer_begin(buf), "END_MSG_CACHE")!=0) {
|
||||
if(!load_msg(ssl, buf, worker))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
load_cache(SSL* ssl, struct worker* worker)
|
||||
{
|
||||
if(!load_rrset_cache(ssl, worker))
|
||||
return 0;
|
||||
if(!load_msg_cache(ssl, worker))
|
||||
return 0;
|
||||
return read_fixed(ssl, worker->env.scratch_buffer, "EOF");
|
||||
}
|
||||
|
||||
/** print details on a delegation point */
|
||||
static void
|
||||
print_dp_details(SSL* ssl, struct worker* worker, struct delegpt* dp)
|
||||
{
|
||||
char buf[257];
|
||||
struct delegpt_addr* a;
|
||||
int lame, dlame, rlame, rto, edns_vs, to, delay, entry_ttl,
|
||||
tA = 0, tAAAA = 0, tother = 0;
|
||||
struct rtt_info ri;
|
||||
uint8_t edns_lame_known;
|
||||
for(a = dp->target_list; a; a = a->next_target) {
|
||||
addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf));
|
||||
if(!ssl_printf(ssl, "%-16s\t", buf))
|
||||
return;
|
||||
if(a->bogus) {
|
||||
if(!ssl_printf(ssl, "Address is BOGUS. "))
|
||||
return;
|
||||
}
|
||||
/* lookup in infra cache */
|
||||
delay=0;
|
||||
entry_ttl = infra_get_host_rto(worker->env.infra_cache,
|
||||
&a->addr, a->addrlen, dp->name, dp->namelen,
|
||||
&ri, &delay, *worker->env.now, &tA, &tAAAA, &tother);
|
||||
if(entry_ttl == -2 && ri.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
|
||||
if(!ssl_printf(ssl, "expired, rto %d msec, tA %d "
|
||||
"tAAAA %d tother %d.\n", ri.rto, tA, tAAAA,
|
||||
tother))
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if(entry_ttl == -1 || entry_ttl == -2) {
|
||||
if(!ssl_printf(ssl, "not in infra cache.\n"))
|
||||
return;
|
||||
continue; /* skip stuff not in infra cache */
|
||||
}
|
||||
|
||||
/* uses type_A because most often looked up, but other
|
||||
* lameness won't be reported then */
|
||||
if(!infra_get_lame_rtt(worker->env.infra_cache,
|
||||
&a->addr, a->addrlen, dp->name, dp->namelen,
|
||||
LDNS_RR_TYPE_A, &lame, &dlame, &rlame, &rto,
|
||||
*worker->env.now)) {
|
||||
if(!ssl_printf(ssl, "not in infra cache.\n"))
|
||||
return;
|
||||
continue; /* skip stuff not in infra cache */
|
||||
}
|
||||
if(!ssl_printf(ssl, "%s%s%s%srto %d msec, ttl %d, ping %d "
|
||||
"var %d rtt %d, tA %d, tAAAA %d, tother %d",
|
||||
lame?"LAME ":"", dlame?"NoDNSSEC ":"",
|
||||
a->lame?"AddrWasParentSide ":"",
|
||||
rlame?"NoAuthButRecursive ":"", rto, entry_ttl,
|
||||
ri.srtt, ri.rttvar, rtt_notimeout(&ri),
|
||||
tA, tAAAA, tother))
|
||||
return;
|
||||
if(delay)
|
||||
if(!ssl_printf(ssl, ", probedelay %d", delay))
|
||||
return;
|
||||
if(infra_host(worker->env.infra_cache, &a->addr, a->addrlen,
|
||||
dp->name, dp->namelen, *worker->env.now, &edns_vs,
|
||||
&edns_lame_known, &to)) {
|
||||
if(edns_vs == -1) {
|
||||
if(!ssl_printf(ssl, ", noEDNS%s.",
|
||||
edns_lame_known?" probed":" assumed"))
|
||||
return;
|
||||
} else {
|
||||
if(!ssl_printf(ssl, ", EDNS %d%s.", edns_vs,
|
||||
edns_lame_known?" probed":" assumed"))
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!ssl_printf(ssl, "\n"))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** print main dp info */
|
||||
static void
|
||||
print_dp_main(SSL* ssl, struct delegpt* dp, struct dns_msg* msg)
|
||||
{
|
||||
size_t i, n_ns, n_miss, n_addr, n_res, n_avail;
|
||||
|
||||
/* print the dp */
|
||||
if(msg)
|
||||
for(i=0; i<msg->rep->rrset_count; i++) {
|
||||
struct ub_packed_rrset_key* k = msg->rep->rrsets[i];
|
||||
struct packed_rrset_data* d =
|
||||
(struct packed_rrset_data*)k->entry.data;
|
||||
if(d->security == sec_status_bogus) {
|
||||
if(!ssl_printf(ssl, "Address is BOGUS:\n"))
|
||||
return;
|
||||
}
|
||||
if(!dump_rrset(ssl, k, d, 0))
|
||||
return;
|
||||
}
|
||||
delegpt_count_ns(dp, &n_ns, &n_miss);
|
||||
delegpt_count_addr(dp, &n_addr, &n_res, &n_avail);
|
||||
/* since dp has not been used by iterator, all are available*/
|
||||
if(!ssl_printf(ssl, "Delegation with %d names, of which %d "
|
||||
"can be examined to query further addresses.\n"
|
||||
"%sIt provides %d IP addresses.\n",
|
||||
(int)n_ns, (int)n_miss, (dp->bogus?"It is BOGUS. ":""),
|
||||
(int)n_addr))
|
||||
return;
|
||||
}
|
||||
|
||||
int print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm,
|
||||
size_t nmlen, int ATTR_UNUSED(nmlabs))
|
||||
{
|
||||
/* deep links into the iterator module */
|
||||
struct delegpt* dp;
|
||||
struct dns_msg* msg;
|
||||
struct regional* region = worker->scratchpad;
|
||||
char b[260];
|
||||
struct query_info qinfo;
|
||||
struct iter_hints_stub* stub;
|
||||
regional_free_all(region);
|
||||
qinfo.qname = nm;
|
||||
qinfo.qname_len = nmlen;
|
||||
qinfo.qtype = LDNS_RR_TYPE_A;
|
||||
qinfo.qclass = LDNS_RR_CLASS_IN;
|
||||
|
||||
dname_str(nm, b);
|
||||
if(!ssl_printf(ssl, "The following name servers are used for lookup "
|
||||
"of %s\n", b))
|
||||
return 0;
|
||||
|
||||
dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass);
|
||||
if(dp) {
|
||||
if(!ssl_printf(ssl, "forwarding request:\n"))
|
||||
return 0;
|
||||
print_dp_main(ssl, dp, NULL);
|
||||
print_dp_details(ssl, worker, dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
dp = dns_cache_find_delegation(&worker->env, nm, nmlen,
|
||||
qinfo.qtype, qinfo.qclass, region, &msg,
|
||||
*worker->env.now);
|
||||
if(!dp) {
|
||||
return ssl_printf(ssl, "no delegation from "
|
||||
"cache; goes to configured roots\n");
|
||||
}
|
||||
/* go up? */
|
||||
if(iter_dp_is_useless(&qinfo, BIT_RD, dp)) {
|
||||
print_dp_main(ssl, dp, msg);
|
||||
print_dp_details(ssl, worker, dp);
|
||||
if(!ssl_printf(ssl, "cache delegation was "
|
||||
"useless (no IP addresses)\n"))
|
||||
return 0;
|
||||
if(dname_is_root(nm)) {
|
||||
/* goes to root config */
|
||||
return ssl_printf(ssl, "no delegation from "
|
||||
"cache; goes to configured roots\n");
|
||||
} else {
|
||||
/* useless, goes up */
|
||||
nm = dp->name;
|
||||
nmlen = dp->namelen;
|
||||
dname_remove_label(&nm, &nmlen);
|
||||
dname_str(nm, b);
|
||||
if(!ssl_printf(ssl, "going up, lookup %s\n", b))
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass,
|
||||
dp);
|
||||
if(stub) {
|
||||
if(stub->noprime) {
|
||||
if(!ssl_printf(ssl, "The noprime stub servers "
|
||||
"are used:\n"))
|
||||
return 0;
|
||||
} else {
|
||||
if(!ssl_printf(ssl, "The stub is primed "
|
||||
"with servers:\n"))
|
||||
return 0;
|
||||
}
|
||||
print_dp_main(ssl, stub->dp, NULL);
|
||||
print_dp_details(ssl, worker, stub->dp);
|
||||
} else {
|
||||
print_dp_main(ssl, dp, msg);
|
||||
print_dp_details(ssl, worker, dp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
107
contrib/unbound/daemon/cachedump.h
Normal file
107
contrib/unbound/daemon/cachedump.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* daemon/cachedump.h - dump the cache to text format.
|
||||
*
|
||||
* Copyright (c) 2008, 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
|
||||
*
|
||||
* This file contains functions to read and write the cache(s)
|
||||
* to text format.
|
||||
*
|
||||
* The format of the file is as follows:
|
||||
* [RRset cache]
|
||||
* [Message cache]
|
||||
* EOF -- fixed string "EOF" before end of the file.
|
||||
*
|
||||
* The RRset cache is:
|
||||
* START_RRSET_CACHE
|
||||
* [rrset]*
|
||||
* END_RRSET_CACHE
|
||||
*
|
||||
* rrset is:
|
||||
* ;rrset [nsec_apex] TTL rr_count rrsig_count trust security
|
||||
* resource records, one per line, in zonefile format
|
||||
* rrsig records, one per line, in zonefile format
|
||||
* If the text conversion fails, BADRR is printed on the line.
|
||||
*
|
||||
* The Message cache is:
|
||||
* START_MSG_CACHE
|
||||
* [msg]*
|
||||
* END_MSG_CACHE
|
||||
*
|
||||
* msg is:
|
||||
* msg name class type flags qdcount ttl security an ns ar
|
||||
* list of rrset references, one per line. If conversion fails, BADREF
|
||||
* reference is:
|
||||
* name class type flags
|
||||
*
|
||||
* Expired cache entries are not printed.
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_DUMPCACHE_H
|
||||
#define DAEMON_DUMPCACHE_H
|
||||
struct worker;
|
||||
|
||||
/**
|
||||
* Dump cache(s) to text
|
||||
* @param ssl: to print to
|
||||
* @param worker: worker that is available (buffers, etc) and has
|
||||
* ptrs to the caches.
|
||||
* @return false on ssl print error.
|
||||
*/
|
||||
int dump_cache(SSL* ssl, struct worker* worker);
|
||||
|
||||
/**
|
||||
* Load cache(s) from text
|
||||
* @param ssl: to read from
|
||||
* @param worker: worker that is available (buffers, etc) and has
|
||||
* ptrs to the caches.
|
||||
* @return false on ssl error.
|
||||
*/
|
||||
int load_cache(SSL* ssl, struct worker* worker);
|
||||
|
||||
/**
|
||||
* Print the delegation used to lookup for this name.
|
||||
* @param ssl: to read from
|
||||
* @param worker: worker that is available (buffers, etc) and has
|
||||
* ptrs to the caches.
|
||||
* @param nm: name to lookup
|
||||
* @param nmlen: length of name.
|
||||
* @param nmlabs: labels in name.
|
||||
* @return false on ssl error.
|
||||
*/
|
||||
int print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm,
|
||||
size_t nmlen, int nmlabs);
|
||||
|
||||
#endif /* DAEMON_DUMPCACHE_H */
|
589
contrib/unbound/daemon/daemon.c
Normal file
589
contrib/unbound/daemon/daemon.c
Normal file
@ -0,0 +1,589 @@
|
||||
/*
|
||||
* daemon/daemon.c - collection of workers that handles requests.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* The daemon consists of global settings and a number of workers.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_OPENSSL_ERR_H
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_RAND_H
|
||||
#include <openssl/rand.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_CONF_H
|
||||
#include <openssl/conf.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_ENGINE_H
|
||||
#include <openssl/engine.h>
|
||||
#endif
|
||||
#include <ldns/ldns.h>
|
||||
#include "daemon/daemon.h"
|
||||
#include "daemon/worker.h"
|
||||
#include "daemon/remote.h"
|
||||
#include "daemon/acl_list.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/storage/lookup3.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/localzone.h"
|
||||
#include "services/modstack.h"
|
||||
#include "util/module.h"
|
||||
#include "util/random.h"
|
||||
#include "util/tube.h"
|
||||
#include <signal.h>
|
||||
|
||||
/** How many quit requests happened. */
|
||||
static int sig_record_quit = 0;
|
||||
/** How many reload requests happened. */
|
||||
static int sig_record_reload = 0;
|
||||
|
||||
#if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS
|
||||
/** cleaner ssl memory freeup */
|
||||
static void* comp_meth = NULL;
|
||||
#endif
|
||||
#ifdef LEX_HAS_YYLEX_DESTROY
|
||||
/** remove buffers for parsing and init */
|
||||
int ub_c_lex_destroy(void);
|
||||
#endif
|
||||
|
||||
/** used when no other sighandling happens, so we don't die
|
||||
* when multiple signals in quick succession are sent to us.
|
||||
* @param sig: signal number.
|
||||
* @return signal handler return type (void or int).
|
||||
*/
|
||||
static RETSIGTYPE record_sigh(int sig)
|
||||
{
|
||||
#ifdef LIBEVENT_SIGNAL_PROBLEM
|
||||
verbose(VERB_OPS, "quit on signal, no cleanup and statistics, "
|
||||
"because installed libevent version is not threadsafe");
|
||||
exit(0);
|
||||
#endif
|
||||
switch(sig)
|
||||
{
|
||||
case SIGTERM:
|
||||
#ifdef SIGQUIT
|
||||
case SIGQUIT:
|
||||
#endif
|
||||
#ifdef SIGBREAK
|
||||
case SIGBREAK:
|
||||
#endif
|
||||
case SIGINT:
|
||||
sig_record_quit++;
|
||||
break;
|
||||
#ifdef SIGHUP
|
||||
case SIGHUP:
|
||||
sig_record_reload++;
|
||||
break;
|
||||
#endif
|
||||
#ifdef SIGPIPE
|
||||
case SIGPIPE:
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
log_err("ignoring signal %d", sig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal handling during the time when netevent is disabled.
|
||||
* Stores signals to replay later.
|
||||
*/
|
||||
static void
|
||||
signal_handling_record(void)
|
||||
{
|
||||
if( signal(SIGTERM, record_sigh) == SIG_ERR ||
|
||||
#ifdef SIGQUIT
|
||||
signal(SIGQUIT, record_sigh) == SIG_ERR ||
|
||||
#endif
|
||||
#ifdef SIGBREAK
|
||||
signal(SIGBREAK, record_sigh) == SIG_ERR ||
|
||||
#endif
|
||||
#ifdef SIGHUP
|
||||
signal(SIGHUP, record_sigh) == SIG_ERR ||
|
||||
#endif
|
||||
#ifdef SIGPIPE
|
||||
signal(SIGPIPE, SIG_IGN) == SIG_ERR ||
|
||||
#endif
|
||||
signal(SIGINT, record_sigh) == SIG_ERR
|
||||
)
|
||||
log_err("install sighandler: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replay old signals.
|
||||
* @param wrk: worker that handles signals.
|
||||
*/
|
||||
static void
|
||||
signal_handling_playback(struct worker* wrk)
|
||||
{
|
||||
#ifdef SIGHUP
|
||||
if(sig_record_reload)
|
||||
worker_sighandler(SIGHUP, wrk);
|
||||
#endif
|
||||
if(sig_record_quit)
|
||||
worker_sighandler(SIGTERM, wrk);
|
||||
sig_record_quit = 0;
|
||||
sig_record_reload = 0;
|
||||
}
|
||||
|
||||
struct daemon*
|
||||
daemon_init(void)
|
||||
{
|
||||
struct daemon* daemon = (struct daemon*)calloc(1,
|
||||
sizeof(struct daemon));
|
||||
#ifdef USE_WINSOCK
|
||||
int r;
|
||||
WSADATA wsa_data;
|
||||
#endif
|
||||
if(!daemon)
|
||||
return NULL;
|
||||
#ifdef USE_WINSOCK
|
||||
r = WSAStartup(MAKEWORD(2,2), &wsa_data);
|
||||
if(r != 0) {
|
||||
fatal_exit("could not init winsock. WSAStartup: %s",
|
||||
wsa_strerror(r));
|
||||
}
|
||||
#endif /* USE_WINSOCK */
|
||||
signal_handling_record();
|
||||
checklock_start();
|
||||
ERR_load_crypto_strings();
|
||||
ERR_load_SSL_strings();
|
||||
#ifdef HAVE_OPENSSL_CONFIG
|
||||
OPENSSL_config("unbound");
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
(void)ldns_key_EVP_load_gost_id();
|
||||
#endif
|
||||
OpenSSL_add_all_algorithms();
|
||||
#if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS
|
||||
/* grab the COMP method ptr because openssl leaks it */
|
||||
comp_meth = (void*)SSL_COMP_get_compression_methods();
|
||||
#endif
|
||||
(void)SSL_library_init();
|
||||
#ifdef HAVE_TZSET
|
||||
/* init timezone info while we are not chrooted yet */
|
||||
tzset();
|
||||
#endif
|
||||
/* open /dev/random if needed */
|
||||
ub_systemseed((unsigned)time(NULL)^(unsigned)getpid()^0xe67);
|
||||
daemon->need_to_exit = 0;
|
||||
modstack_init(&daemon->mods);
|
||||
if(!(daemon->env = (struct module_env*)calloc(1,
|
||||
sizeof(*daemon->env)))) {
|
||||
free(daemon);
|
||||
return NULL;
|
||||
}
|
||||
alloc_init(&daemon->superalloc, NULL, 0);
|
||||
daemon->acl = acl_list_create();
|
||||
if(!daemon->acl) {
|
||||
free(daemon->env);
|
||||
free(daemon);
|
||||
return NULL;
|
||||
}
|
||||
if(gettimeofday(&daemon->time_boot, NULL) < 0)
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
daemon->time_last_stat = daemon->time_boot;
|
||||
return daemon;
|
||||
}
|
||||
|
||||
int
|
||||
daemon_open_shared_ports(struct daemon* daemon)
|
||||
{
|
||||
log_assert(daemon);
|
||||
if(daemon->cfg->port != daemon->listening_port) {
|
||||
listening_ports_free(daemon->ports);
|
||||
if(!(daemon->ports=listening_ports_open(daemon->cfg)))
|
||||
return 0;
|
||||
daemon->listening_port = daemon->cfg->port;
|
||||
}
|
||||
if(!daemon->cfg->remote_control_enable && daemon->rc_port) {
|
||||
listening_ports_free(daemon->rc_ports);
|
||||
daemon->rc_ports = NULL;
|
||||
daemon->rc_port = 0;
|
||||
}
|
||||
if(daemon->cfg->remote_control_enable &&
|
||||
daemon->cfg->control_port != daemon->rc_port) {
|
||||
listening_ports_free(daemon->rc_ports);
|
||||
if(!(daemon->rc_ports=daemon_remote_open_ports(daemon->cfg)))
|
||||
return 0;
|
||||
daemon->rc_port = daemon->cfg->control_port;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup modules. setup module stack.
|
||||
* @param daemon: the daemon
|
||||
*/
|
||||
static void daemon_setup_modules(struct daemon* daemon)
|
||||
{
|
||||
daemon->env->cfg = daemon->cfg;
|
||||
daemon->env->alloc = &daemon->superalloc;
|
||||
daemon->env->worker = NULL;
|
||||
daemon->env->need_to_validate = 0; /* set by module init below */
|
||||
if(!modstack_setup(&daemon->mods, daemon->cfg->module_conf,
|
||||
daemon->env)) {
|
||||
fatal_exit("failed to setup modules");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain allowed port numbers, concatenate the list, and shuffle them
|
||||
* (ready to be handed out to threads).
|
||||
* @param daemon: the daemon. Uses rand and cfg.
|
||||
* @param shufport: the portlist output.
|
||||
* @return number of ports available.
|
||||
*/
|
||||
static int daemon_get_shufport(struct daemon* daemon, int* shufport)
|
||||
{
|
||||
int i, n, k, temp;
|
||||
int avail = 0;
|
||||
for(i=0; i<65536; i++) {
|
||||
if(daemon->cfg->outgoing_avail_ports[i]) {
|
||||
shufport[avail++] = daemon->cfg->
|
||||
outgoing_avail_ports[i];
|
||||
}
|
||||
}
|
||||
if(avail == 0)
|
||||
fatal_exit("no ports are permitted for UDP, add "
|
||||
"with outgoing-port-permit");
|
||||
/* Knuth shuffle */
|
||||
n = avail;
|
||||
while(--n > 0) {
|
||||
k = ub_random_max(daemon->rand, n+1); /* 0<= k<= n */
|
||||
temp = shufport[k];
|
||||
shufport[k] = shufport[n];
|
||||
shufport[n] = temp;
|
||||
}
|
||||
return avail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate empty worker structures. With backptr and thread-number,
|
||||
* from 0..numthread initialised. Used as user arguments to new threads.
|
||||
* Creates the daemon random generator if it does not exist yet.
|
||||
* The random generator stays existing between reloads with a unique state.
|
||||
* @param daemon: the daemon with (new) config settings.
|
||||
*/
|
||||
static void
|
||||
daemon_create_workers(struct daemon* daemon)
|
||||
{
|
||||
int i, numport;
|
||||
int* shufport;
|
||||
log_assert(daemon && daemon->cfg);
|
||||
if(!daemon->rand) {
|
||||
unsigned int seed = (unsigned int)time(NULL) ^
|
||||
(unsigned int)getpid() ^ 0x438;
|
||||
daemon->rand = ub_initstate(seed, NULL);
|
||||
if(!daemon->rand)
|
||||
fatal_exit("could not init random generator");
|
||||
}
|
||||
hash_set_raninit((uint32_t)ub_random(daemon->rand));
|
||||
shufport = (int*)calloc(65536, sizeof(int));
|
||||
if(!shufport)
|
||||
fatal_exit("out of memory during daemon init");
|
||||
numport = daemon_get_shufport(daemon, shufport);
|
||||
verbose(VERB_ALGO, "total of %d outgoing ports available", numport);
|
||||
|
||||
daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1);
|
||||
daemon->workers = (struct worker**)calloc((size_t)daemon->num,
|
||||
sizeof(struct worker*));
|
||||
for(i=0; i<daemon->num; i++) {
|
||||
if(!(daemon->workers[i] = worker_create(daemon, i,
|
||||
shufport+numport*i/daemon->num,
|
||||
numport*(i+1)/daemon->num - numport*i/daemon->num)))
|
||||
/* the above is not ports/numthr, due to rounding */
|
||||
fatal_exit("could not create worker");
|
||||
}
|
||||
free(shufport);
|
||||
}
|
||||
|
||||
#ifdef THREADS_DISABLED
|
||||
/**
|
||||
* Close all pipes except for the numbered thread.
|
||||
* @param daemon: daemon to close pipes in.
|
||||
* @param thr: thread number 0..num-1 of thread to skip.
|
||||
*/
|
||||
static void close_other_pipes(struct daemon* daemon, int thr)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<daemon->num; i++)
|
||||
if(i!=thr) {
|
||||
if(i==0) {
|
||||
/* only close read part, need to write stats */
|
||||
tube_close_read(daemon->workers[i]->cmd);
|
||||
} else {
|
||||
/* complete close channel to others */
|
||||
tube_delete(daemon->workers[i]->cmd);
|
||||
daemon->workers[i]->cmd = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* THREADS_DISABLED */
|
||||
|
||||
/**
|
||||
* Function to start one thread.
|
||||
* @param arg: user argument.
|
||||
* @return: void* user return value could be used for thread_join results.
|
||||
*/
|
||||
static void*
|
||||
thread_start(void* arg)
|
||||
{
|
||||
struct worker* worker = (struct worker*)arg;
|
||||
log_thread_set(&worker->thread_num);
|
||||
ub_thread_blocksigs();
|
||||
#ifdef THREADS_DISABLED
|
||||
/* close pipe ends used by main */
|
||||
tube_close_write(worker->cmd);
|
||||
close_other_pipes(worker->daemon, worker->thread_num);
|
||||
#endif
|
||||
if(!worker_init(worker, worker->daemon->cfg, worker->daemon->ports, 0))
|
||||
fatal_exit("Could not initialize thread");
|
||||
|
||||
worker_work(worker);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fork and init the other threads. Main thread returns for special handling.
|
||||
* @param daemon: the daemon with other threads to fork.
|
||||
*/
|
||||
static void
|
||||
daemon_start_others(struct daemon* daemon)
|
||||
{
|
||||
int i;
|
||||
log_assert(daemon);
|
||||
verbose(VERB_ALGO, "start threads");
|
||||
/* skip i=0, is this thread */
|
||||
for(i=1; i<daemon->num; i++) {
|
||||
ub_thread_create(&daemon->workers[i]->thr_id,
|
||||
thread_start, daemon->workers[i]);
|
||||
#ifdef THREADS_DISABLED
|
||||
/* close pipe end of child */
|
||||
tube_close_read(daemon->workers[i]->cmd);
|
||||
#endif /* no threads */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the other threads.
|
||||
* @param daemon: the daemon with other threads.
|
||||
*/
|
||||
static void
|
||||
daemon_stop_others(struct daemon* daemon)
|
||||
{
|
||||
int i;
|
||||
log_assert(daemon);
|
||||
verbose(VERB_ALGO, "stop threads");
|
||||
/* skip i=0, is this thread */
|
||||
/* use i=0 buffer for sending cmds; because we are #0 */
|
||||
for(i=1; i<daemon->num; i++) {
|
||||
worker_send_cmd(daemon->workers[i], worker_cmd_quit);
|
||||
}
|
||||
/* wait for them to quit */
|
||||
for(i=1; i<daemon->num; i++) {
|
||||
/* join it to make sure its dead */
|
||||
verbose(VERB_ALGO, "join %d", i);
|
||||
ub_thread_join(daemon->workers[i]->thr_id);
|
||||
verbose(VERB_ALGO, "join success %d", i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
daemon_fork(struct daemon* daemon)
|
||||
{
|
||||
log_assert(daemon);
|
||||
if(!acl_list_apply_cfg(daemon->acl, daemon->cfg))
|
||||
fatal_exit("Could not setup access control list");
|
||||
if(!(daemon->local_zones = local_zones_create()))
|
||||
fatal_exit("Could not create local zones: out of memory");
|
||||
if(!local_zones_apply_cfg(daemon->local_zones, daemon->cfg))
|
||||
fatal_exit("Could not set up local zones");
|
||||
|
||||
/* setup modules */
|
||||
daemon_setup_modules(daemon);
|
||||
|
||||
/* first create all the worker structures, so we can pass
|
||||
* them to the newly created threads.
|
||||
*/
|
||||
daemon_create_workers(daemon);
|
||||
|
||||
#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
|
||||
/* in libev the first inited base gets signals */
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports, 1))
|
||||
fatal_exit("Could not initialize main thread");
|
||||
#endif
|
||||
|
||||
/* Now create the threads and init the workers.
|
||||
* By the way, this is thread #0 (the main thread).
|
||||
*/
|
||||
daemon_start_others(daemon);
|
||||
|
||||
/* Special handling for the main thread. This is the thread
|
||||
* that handles signals and remote control.
|
||||
*/
|
||||
#if !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP))
|
||||
/* libevent has the last inited base get signals (or any base) */
|
||||
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports, 1))
|
||||
fatal_exit("Could not initialize main thread");
|
||||
#endif
|
||||
signal_handling_playback(daemon->workers[0]);
|
||||
|
||||
/* Start resolver service on main thread. */
|
||||
log_info("start of service (%s).", PACKAGE_STRING);
|
||||
worker_work(daemon->workers[0]);
|
||||
log_info("service stopped (%s).", PACKAGE_STRING);
|
||||
|
||||
/* we exited! a signal happened! Stop other threads */
|
||||
daemon_stop_others(daemon);
|
||||
|
||||
daemon->need_to_exit = daemon->workers[0]->need_to_exit;
|
||||
}
|
||||
|
||||
void
|
||||
daemon_cleanup(struct daemon* daemon)
|
||||
{
|
||||
int i;
|
||||
log_assert(daemon);
|
||||
/* before stopping main worker, handle signals ourselves, so we
|
||||
don't die on multiple reload signals for example. */
|
||||
signal_handling_record();
|
||||
log_thread_set(NULL);
|
||||
/* clean up caches because
|
||||
* a) RRset IDs will be recycled after a reload, causing collisions
|
||||
* b) validation config can change, thus rrset, msg, keycache clear
|
||||
* The infra cache is kept, the timing and edns info is still valid */
|
||||
slabhash_clear(&daemon->env->rrset_cache->table);
|
||||
slabhash_clear(daemon->env->msg_cache);
|
||||
local_zones_delete(daemon->local_zones);
|
||||
daemon->local_zones = NULL;
|
||||
/* key cache is cleared by module desetup during next daemon_init() */
|
||||
daemon_remote_clear(daemon->rc);
|
||||
for(i=0; i<daemon->num; i++)
|
||||
worker_delete(daemon->workers[i]);
|
||||
free(daemon->workers);
|
||||
daemon->workers = NULL;
|
||||
daemon->num = 0;
|
||||
daemon->cfg = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
daemon_delete(struct daemon* daemon)
|
||||
{
|
||||
if(!daemon)
|
||||
return;
|
||||
modstack_desetup(&daemon->mods, daemon->env);
|
||||
daemon_remote_delete(daemon->rc);
|
||||
listening_ports_free(daemon->ports);
|
||||
listening_ports_free(daemon->rc_ports);
|
||||
if(daemon->env) {
|
||||
slabhash_delete(daemon->env->msg_cache);
|
||||
rrset_cache_delete(daemon->env->rrset_cache);
|
||||
infra_delete(daemon->env->infra_cache);
|
||||
}
|
||||
ub_randfree(daemon->rand);
|
||||
alloc_clear(&daemon->superalloc);
|
||||
acl_list_delete(daemon->acl);
|
||||
free(daemon->chroot);
|
||||
free(daemon->pidfile);
|
||||
free(daemon->env);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->connect_sslctx);
|
||||
free(daemon);
|
||||
#ifdef LEX_HAS_YYLEX_DESTROY
|
||||
/* lex cleanup */
|
||||
ub_c_lex_destroy();
|
||||
#endif
|
||||
/* libcrypto cleanup */
|
||||
#if defined(USE_GOST) && defined(HAVE_LDNS_KEY_EVP_UNLOAD_GOST)
|
||||
ldns_key_EVP_unload_gost();
|
||||
#endif
|
||||
#if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE
|
||||
#ifndef S_SPLINT_S
|
||||
sk_SSL_COMP_pop_free(comp_meth, (void(*)())CRYPTO_free);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_OPENSSL_CONFIG
|
||||
EVP_cleanup();
|
||||
ENGINE_cleanup();
|
||||
CONF_modules_free();
|
||||
#endif
|
||||
CRYPTO_cleanup_all_ex_data(); /* safe, no more threads right now */
|
||||
ERR_remove_state(0);
|
||||
ERR_free_strings();
|
||||
RAND_cleanup();
|
||||
checklock_stop();
|
||||
#ifdef USE_WINSOCK
|
||||
if(WSACleanup() != 0) {
|
||||
log_err("Could not WSACleanup: %s",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
daemon->cfg = cfg;
|
||||
config_apply(cfg);
|
||||
if(!daemon->env->msg_cache ||
|
||||
cfg->msg_cache_size != slabhash_get_size(daemon->env->msg_cache) ||
|
||||
cfg->msg_cache_slabs != daemon->env->msg_cache->size) {
|
||||
slabhash_delete(daemon->env->msg_cache);
|
||||
daemon->env->msg_cache = slabhash_create(cfg->msg_cache_slabs,
|
||||
HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
|
||||
msgreply_sizefunc, query_info_compare,
|
||||
query_entry_delete, reply_info_delete, NULL);
|
||||
if(!daemon->env->msg_cache) {
|
||||
fatal_exit("malloc failure updating config settings");
|
||||
}
|
||||
}
|
||||
if((daemon->env->rrset_cache = rrset_cache_adjust(
|
||||
daemon->env->rrset_cache, cfg, &daemon->superalloc)) == 0)
|
||||
fatal_exit("malloc failure updating config settings");
|
||||
if((daemon->env->infra_cache = infra_adjust(daemon->env->infra_cache,
|
||||
cfg))==0)
|
||||
fatal_exit("malloc failure updating config settings");
|
||||
}
|
150
contrib/unbound/daemon/daemon.h
Normal file
150
contrib/unbound/daemon/daemon.h
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* daemon/daemon.h - collection of workers that handles requests.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* The daemon consists of global settings and a number of workers.
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_H
|
||||
#define DAEMON_H
|
||||
|
||||
#include "util/locks.h"
|
||||
#include "util/alloc.h"
|
||||
#include "services/modstack.h"
|
||||
#ifdef UB_ON_WINDOWS
|
||||
# include "util/winsock_event.h"
|
||||
#endif
|
||||
struct config_file;
|
||||
struct worker;
|
||||
struct listen_port;
|
||||
struct slabhash;
|
||||
struct module_env;
|
||||
struct rrset_cache;
|
||||
struct acl_list;
|
||||
struct local_zones;
|
||||
struct ub_randstate;
|
||||
struct daemon_remote;
|
||||
|
||||
/**
|
||||
* Structure holding worker list.
|
||||
* Holds globally visible information.
|
||||
*/
|
||||
struct daemon {
|
||||
/** The config settings */
|
||||
struct config_file* cfg;
|
||||
/** the chroot dir in use, NULL if none */
|
||||
char* chroot;
|
||||
/** pidfile that is used */
|
||||
char* pidfile;
|
||||
/** port number that has ports opened. */
|
||||
int listening_port;
|
||||
/** listening ports, opened, to be shared by threads */
|
||||
struct listen_port* ports;
|
||||
/** port number for remote that has ports opened. */
|
||||
int rc_port;
|
||||
/** listening ports for remote control */
|
||||
struct listen_port* rc_ports;
|
||||
/** remote control connections management (for first worker) */
|
||||
struct daemon_remote* rc;
|
||||
/** ssl context for listening to dnstcp over ssl, and connecting ssl */
|
||||
void* listen_sslctx, *connect_sslctx;
|
||||
/** num threads allocated */
|
||||
int num;
|
||||
/** the worker entries */
|
||||
struct worker** workers;
|
||||
/** do we need to exit unbound (or is it only a reload?) */
|
||||
int need_to_exit;
|
||||
/** master random table ; used for port div between threads on reload*/
|
||||
struct ub_randstate* rand;
|
||||
/** master allocation cache */
|
||||
struct alloc_cache superalloc;
|
||||
/** the module environment master value, copied and changed by threads*/
|
||||
struct module_env* env;
|
||||
/** stack of module callbacks */
|
||||
struct module_stack mods;
|
||||
/** access control, which client IPs are allowed to connect */
|
||||
struct acl_list* acl;
|
||||
/** local authority zones */
|
||||
struct local_zones* local_zones;
|
||||
/** last time of statistics printout */
|
||||
struct timeval time_last_stat;
|
||||
/** time when daemon started */
|
||||
struct timeval time_boot;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize daemon structure.
|
||||
* @return: The daemon structure, or NULL on error.
|
||||
*/
|
||||
struct daemon* daemon_init(void);
|
||||
|
||||
/**
|
||||
* Open shared listening ports (if needed).
|
||||
* The cfg member pointer must have been set for the daemon.
|
||||
* @param daemon: the daemon.
|
||||
* @return: false on error.
|
||||
*/
|
||||
int daemon_open_shared_ports(struct daemon* daemon);
|
||||
|
||||
/**
|
||||
* Fork workers and start service.
|
||||
* When the routine exits, it is no longer forked.
|
||||
* @param daemon: the daemon.
|
||||
*/
|
||||
void daemon_fork(struct daemon* daemon);
|
||||
|
||||
/**
|
||||
* Close off the worker thread information.
|
||||
* Bring the daemon back into state ready for daemon_fork again.
|
||||
* @param daemon: the daemon.
|
||||
*/
|
||||
void daemon_cleanup(struct daemon* daemon);
|
||||
|
||||
/**
|
||||
* Delete workers, close listening ports.
|
||||
* @param daemon: the daemon.
|
||||
*/
|
||||
void daemon_delete(struct daemon* daemon);
|
||||
|
||||
/**
|
||||
* Apply config settings.
|
||||
* @param daemon: the daemon.
|
||||
* @param cfg: new config settings.
|
||||
*/
|
||||
void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg);
|
||||
|
||||
#endif /* DAEMON_H */
|
2179
contrib/unbound/daemon/remote.c
Normal file
2179
contrib/unbound/daemon/remote.c
Normal file
File diff suppressed because it is too large
Load Diff
192
contrib/unbound/daemon/remote.h
Normal file
192
contrib/unbound/daemon/remote.h
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* daemon/remote.h - remote control for the unbound daemon.
|
||||
*
|
||||
* Copyright (c) 2008, 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
|
||||
*
|
||||
* This file contains the remote control functionality for the daemon.
|
||||
* The remote control can be performed using either the commandline
|
||||
* unbound-control tool, or a SSLv3/TLS capable web browser.
|
||||
* The channel is secured using SSLv3 or TLSv1, and certificates.
|
||||
* Both the server and the client(control tool) have their own keys.
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_REMOTE_H
|
||||
#define DAEMON_REMOTE_H
|
||||
#ifdef HAVE_OPENSSL_SSL_H
|
||||
#include "openssl/ssl.h"
|
||||
#endif
|
||||
struct config_file;
|
||||
struct listen_list;
|
||||
struct listen_port;
|
||||
struct worker;
|
||||
struct comm_reply;
|
||||
struct comm_point;
|
||||
struct daemon_remote;
|
||||
|
||||
/** number of seconds timeout on incoming remote control handshake */
|
||||
#define REMOTE_CONTROL_TCP_TIMEOUT 120
|
||||
|
||||
/**
|
||||
* a busy control command connection, SSL state
|
||||
*/
|
||||
struct rc_state {
|
||||
/** the next item in list */
|
||||
struct rc_state* next;
|
||||
/** the commpoint */
|
||||
struct comm_point* c;
|
||||
/** in the handshake part */
|
||||
enum { rc_none, rc_hs_read, rc_hs_write } shake_state;
|
||||
/** the ssl state */
|
||||
SSL* ssl;
|
||||
/** the rc this is part of */
|
||||
struct daemon_remote* rc;
|
||||
};
|
||||
|
||||
/**
|
||||
* The remote control tool state.
|
||||
* The state is only created for the first thread, other threads
|
||||
* are called from this thread. Only the first threads listens to
|
||||
* the control port. The other threads do not, but are called on the
|
||||
* command channel(pipe) from the first thread.
|
||||
*/
|
||||
struct daemon_remote {
|
||||
/** the worker for this remote control */
|
||||
struct worker* worker;
|
||||
/** commpoints for accepting remote control connections */
|
||||
struct listen_list* accept_list;
|
||||
/** number of active commpoints that are handling remote control */
|
||||
int active;
|
||||
/** max active commpoints */
|
||||
int max_active;
|
||||
/** current commpoints busy; should be a short list, malloced */
|
||||
struct rc_state* busy_list;
|
||||
/** the SSL context for creating new SSL streams */
|
||||
SSL_CTX* ctx;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create new remote control state for the daemon.
|
||||
* @param cfg: config file with key file settings.
|
||||
* @return new state, or NULL on failure.
|
||||
*/
|
||||
struct daemon_remote* daemon_remote_create(struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* remote control state to delete.
|
||||
* @param rc: state to delete.
|
||||
*/
|
||||
void daemon_remote_delete(struct daemon_remote* rc);
|
||||
|
||||
/**
|
||||
* remote control state to clear up. Busy and accept points are closed.
|
||||
* Does not delete the rc itself, or the ssl context (with its keys).
|
||||
* @param rc: state to clear.
|
||||
*/
|
||||
void daemon_remote_clear(struct daemon_remote* rc);
|
||||
|
||||
/**
|
||||
* Open and create listening ports for remote control.
|
||||
* @param cfg: config options.
|
||||
* @return list of ports or NULL on failure.
|
||||
* can be freed with listening_ports_free().
|
||||
*/
|
||||
struct listen_port* daemon_remote_open_ports(struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Setup comm points for accepting remote control connections.
|
||||
* @param rc: state
|
||||
* @param ports: already opened ports.
|
||||
* @param worker: worker with communication base. and links to command channels.
|
||||
* @return false on error.
|
||||
*/
|
||||
int daemon_remote_open_accept(struct daemon_remote* rc,
|
||||
struct listen_port* ports, struct worker* worker);
|
||||
|
||||
/**
|
||||
* Stop accept handlers for TCP (until enabled again)
|
||||
* @param rc: state
|
||||
*/
|
||||
void daemon_remote_stop_accept(struct daemon_remote* rc);
|
||||
|
||||
/**
|
||||
* Stop accept handlers for TCP (until enabled again)
|
||||
* @param rc: state
|
||||
*/
|
||||
void daemon_remote_start_accept(struct daemon_remote* rc);
|
||||
|
||||
/**
|
||||
* Handle nonthreaded remote cmd execution.
|
||||
* @param worker: this worker (the remote worker).
|
||||
*/
|
||||
void daemon_remote_exec(struct worker* worker);
|
||||
|
||||
/** handle remote control accept callbacks */
|
||||
int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/** handle remote control data callbacks */
|
||||
int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*);
|
||||
|
||||
/**
|
||||
* Print fixed line of text over ssl connection in blocking mode
|
||||
* @param ssl: print to
|
||||
* @param text: the text.
|
||||
* @return false on connection failure.
|
||||
*/
|
||||
int ssl_print_text(SSL* ssl, const char* text);
|
||||
|
||||
/**
|
||||
* printf style printing to the ssl connection
|
||||
* @param ssl: the SSL connection to print to. Blocking.
|
||||
* @param format: printf style format string.
|
||||
* @return success or false on a network failure.
|
||||
*/
|
||||
int ssl_printf(SSL* ssl, const char* format, ...)
|
||||
ATTR_FORMAT(printf, 2, 3);
|
||||
|
||||
/**
|
||||
* Read until \n is encountered
|
||||
* If SSL signals EOF, the string up to then is returned (without \n).
|
||||
* @param ssl: the SSL connection to read from. blocking.
|
||||
* @param buf: buffer to read to.
|
||||
* @param max: size of buffer.
|
||||
* @return false on connection failure.
|
||||
*/
|
||||
int ssl_read_line(SSL* ssl, char* buf, size_t max);
|
||||
|
||||
/** routine to printout option values over SSL */
|
||||
void remote_get_opt_ssl(char* line, void* arg);
|
||||
|
||||
#endif /* DAEMON_REMOTE_H */
|
303
contrib/unbound/daemon/stats.c
Normal file
303
contrib/unbound/daemon/stats.c
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
* daemon/stats.c - collect runtime performance indicators.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file describes the data structure used to collect runtime performance
|
||||
* numbers. These 'statistics' may be of interest to the operator.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <ldns/wire2host.h>
|
||||
#include "daemon/stats.h"
|
||||
#include "daemon/worker.h"
|
||||
#include "daemon/daemon.h"
|
||||
#include "services/mesh.h"
|
||||
#include "services/outside_network.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/tube.h"
|
||||
#include "util/timehist.h"
|
||||
#include "util/net_help.h"
|
||||
#include "validator/validator.h"
|
||||
|
||||
/** add timers and the values do not overflow or become negative */
|
||||
static void
|
||||
timeval_add(struct timeval* d, const struct timeval* add)
|
||||
{
|
||||
#ifndef S_SPLINT_S
|
||||
d->tv_sec += add->tv_sec;
|
||||
d->tv_usec += add->tv_usec;
|
||||
if(d->tv_usec > 1000000) {
|
||||
d->tv_usec -= 1000000;
|
||||
d->tv_sec++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void server_stats_init(struct server_stats* stats, struct config_file* cfg)
|
||||
{
|
||||
memset(stats, 0, sizeof(*stats));
|
||||
stats->extended = cfg->stat_extended;
|
||||
}
|
||||
|
||||
void server_stats_querymiss(struct server_stats* stats, struct worker* worker)
|
||||
{
|
||||
stats->num_queries_missed_cache++;
|
||||
stats->sum_query_list_size += worker->env.mesh->all.count;
|
||||
if(worker->env.mesh->all.count > stats->max_query_list_size)
|
||||
stats->max_query_list_size = worker->env.mesh->all.count;
|
||||
}
|
||||
|
||||
void server_stats_prefetch(struct server_stats* stats, struct worker* worker)
|
||||
{
|
||||
stats->num_queries_prefetch++;
|
||||
/* changes the query list size so account that, like a querymiss */
|
||||
stats->sum_query_list_size += worker->env.mesh->all.count;
|
||||
if(worker->env.mesh->all.count > stats->max_query_list_size)
|
||||
stats->max_query_list_size = worker->env.mesh->all.count;
|
||||
}
|
||||
|
||||
void server_stats_log(struct server_stats* stats, struct worker* worker,
|
||||
int threadnum)
|
||||
{
|
||||
log_info("server stats for thread %d: %u queries, "
|
||||
"%u answers from cache, %u recursions, %u prefetch",
|
||||
threadnum, (unsigned)stats->num_queries,
|
||||
(unsigned)(stats->num_queries -
|
||||
stats->num_queries_missed_cache),
|
||||
(unsigned)stats->num_queries_missed_cache,
|
||||
(unsigned)stats->num_queries_prefetch);
|
||||
log_info("server stats for thread %d: requestlist max %u avg %g "
|
||||
"exceeded %u jostled %u", threadnum,
|
||||
(unsigned)stats->max_query_list_size,
|
||||
(stats->num_queries_missed_cache+stats->num_queries_prefetch)?
|
||||
(double)stats->sum_query_list_size/
|
||||
(stats->num_queries_missed_cache+
|
||||
stats->num_queries_prefetch) : 0.0,
|
||||
(unsigned)worker->env.mesh->stats_dropped,
|
||||
(unsigned)worker->env.mesh->stats_jostled);
|
||||
}
|
||||
|
||||
/** get rrsets bogus number from validator */
|
||||
static size_t
|
||||
get_rrset_bogus(struct worker* worker)
|
||||
{
|
||||
int m = modstack_find(&worker->env.mesh->mods, "validator");
|
||||
struct val_env* ve;
|
||||
size_t r;
|
||||
if(m == -1)
|
||||
return 0;
|
||||
ve = (struct val_env*)worker->env.modinfo[m];
|
||||
lock_basic_lock(&ve->bogus_lock);
|
||||
r = ve->num_rrset_bogus;
|
||||
if(!worker->env.cfg->stat_cumulative)
|
||||
ve->num_rrset_bogus = 0;
|
||||
lock_basic_unlock(&ve->bogus_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
server_stats_compile(struct worker* worker, struct stats_info* s, int reset)
|
||||
{
|
||||
int i;
|
||||
|
||||
s->svr = worker->stats;
|
||||
s->mesh_num_states = worker->env.mesh->all.count;
|
||||
s->mesh_num_reply_states = worker->env.mesh->num_reply_states;
|
||||
s->mesh_jostled = worker->env.mesh->stats_jostled;
|
||||
s->mesh_dropped = worker->env.mesh->stats_dropped;
|
||||
s->mesh_replies_sent = worker->env.mesh->replies_sent;
|
||||
s->mesh_replies_sum_wait = worker->env.mesh->replies_sum_wait;
|
||||
s->mesh_time_median = timehist_quartile(worker->env.mesh->histogram,
|
||||
0.50);
|
||||
|
||||
/* add in the values from the mesh */
|
||||
s->svr.ans_secure += worker->env.mesh->ans_secure;
|
||||
s->svr.ans_bogus += worker->env.mesh->ans_bogus;
|
||||
s->svr.ans_rcode_nodata += worker->env.mesh->ans_nodata;
|
||||
for(i=0; i<16; i++)
|
||||
s->svr.ans_rcode[i] += worker->env.mesh->ans_rcode[i];
|
||||
timehist_export(worker->env.mesh->histogram, s->svr.hist,
|
||||
NUM_BUCKETS_HIST);
|
||||
/* values from outside network */
|
||||
s->svr.unwanted_replies = worker->back->unwanted_replies;
|
||||
|
||||
/* get and reset validator rrset bogus number */
|
||||
s->svr.rrset_bogus = get_rrset_bogus(worker);
|
||||
|
||||
if(reset && !worker->env.cfg->stat_cumulative) {
|
||||
worker_stats_clear(worker);
|
||||
}
|
||||
}
|
||||
|
||||
void server_stats_obtain(struct worker* worker, struct worker* who,
|
||||
struct stats_info* s, int reset)
|
||||
{
|
||||
uint8_t *reply = NULL;
|
||||
uint32_t len = 0;
|
||||
if(worker == who) {
|
||||
/* just fill it in */
|
||||
server_stats_compile(worker, s, reset);
|
||||
return;
|
||||
}
|
||||
/* communicate over tube */
|
||||
verbose(VERB_ALGO, "write stats cmd");
|
||||
if(reset)
|
||||
worker_send_cmd(who, worker_cmd_stats);
|
||||
else worker_send_cmd(who, worker_cmd_stats_noreset);
|
||||
verbose(VERB_ALGO, "wait for stats reply");
|
||||
if(!tube_read_msg(worker->cmd, &reply, &len, 0))
|
||||
fatal_exit("failed to read stats over cmd channel");
|
||||
if(len != (uint32_t)sizeof(*s))
|
||||
fatal_exit("stats on cmd channel wrong length %d %d",
|
||||
(int)len, (int)sizeof(*s));
|
||||
memcpy(s, reply, (size_t)len);
|
||||
free(reply);
|
||||
}
|
||||
|
||||
void server_stats_reply(struct worker* worker, int reset)
|
||||
{
|
||||
struct stats_info s;
|
||||
server_stats_compile(worker, &s, reset);
|
||||
verbose(VERB_ALGO, "write stats replymsg");
|
||||
if(!tube_write_msg(worker->daemon->workers[0]->cmd,
|
||||
(uint8_t*)&s, sizeof(s), 0))
|
||||
fatal_exit("could not write stat values over cmd channel");
|
||||
}
|
||||
|
||||
void server_stats_add(struct stats_info* total, struct stats_info* a)
|
||||
{
|
||||
total->svr.num_queries += a->svr.num_queries;
|
||||
total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
|
||||
total->svr.num_queries_prefetch += a->svr.num_queries_prefetch;
|
||||
total->svr.sum_query_list_size += a->svr.sum_query_list_size;
|
||||
/* the max size reached is upped to higher of both */
|
||||
if(a->svr.max_query_list_size > total->svr.max_query_list_size)
|
||||
total->svr.max_query_list_size = a->svr.max_query_list_size;
|
||||
|
||||
if(a->svr.extended) {
|
||||
int i;
|
||||
total->svr.qtype_big += a->svr.qtype_big;
|
||||
total->svr.qclass_big += a->svr.qclass_big;
|
||||
total->svr.qtcp += a->svr.qtcp;
|
||||
total->svr.qipv6 += a->svr.qipv6;
|
||||
total->svr.qbit_QR += a->svr.qbit_QR;
|
||||
total->svr.qbit_AA += a->svr.qbit_AA;
|
||||
total->svr.qbit_TC += a->svr.qbit_TC;
|
||||
total->svr.qbit_RD += a->svr.qbit_RD;
|
||||
total->svr.qbit_RA += a->svr.qbit_RA;
|
||||
total->svr.qbit_Z += a->svr.qbit_Z;
|
||||
total->svr.qbit_AD += a->svr.qbit_AD;
|
||||
total->svr.qbit_CD += a->svr.qbit_CD;
|
||||
total->svr.qEDNS += a->svr.qEDNS;
|
||||
total->svr.qEDNS_DO += a->svr.qEDNS_DO;
|
||||
total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata;
|
||||
total->svr.ans_secure += a->svr.ans_secure;
|
||||
total->svr.ans_bogus += a->svr.ans_bogus;
|
||||
total->svr.rrset_bogus += a->svr.rrset_bogus;
|
||||
total->svr.unwanted_replies += a->svr.unwanted_replies;
|
||||
total->svr.unwanted_queries += a->svr.unwanted_queries;
|
||||
for(i=0; i<STATS_QTYPE_NUM; i++)
|
||||
total->svr.qtype[i] += a->svr.qtype[i];
|
||||
for(i=0; i<STATS_QCLASS_NUM; i++)
|
||||
total->svr.qclass[i] += a->svr.qclass[i];
|
||||
for(i=0; i<STATS_OPCODE_NUM; i++)
|
||||
total->svr.qopcode[i] += a->svr.qopcode[i];
|
||||
for(i=0; i<STATS_RCODE_NUM; i++)
|
||||
total->svr.ans_rcode[i] += a->svr.ans_rcode[i];
|
||||
for(i=0; i<NUM_BUCKETS_HIST; i++)
|
||||
total->svr.hist[i] += a->svr.hist[i];
|
||||
}
|
||||
|
||||
total->mesh_num_states += a->mesh_num_states;
|
||||
total->mesh_num_reply_states += a->mesh_num_reply_states;
|
||||
total->mesh_jostled += a->mesh_jostled;
|
||||
total->mesh_dropped += a->mesh_dropped;
|
||||
total->mesh_replies_sent += a->mesh_replies_sent;
|
||||
timeval_add(&total->mesh_replies_sum_wait, &a->mesh_replies_sum_wait);
|
||||
/* the medians are averaged together, this is not as accurate as
|
||||
* taking the median over all of the data, but is good and fast
|
||||
* added up here, division later*/
|
||||
total->mesh_time_median += a->mesh_time_median;
|
||||
}
|
||||
|
||||
void server_stats_insquery(struct server_stats* stats, struct comm_point* c,
|
||||
uint16_t qtype, uint16_t qclass, struct edns_data* edns,
|
||||
struct comm_reply* repinfo)
|
||||
{
|
||||
uint16_t flags = ldns_buffer_read_u16_at(c->buffer, 2);
|
||||
if(qtype < STATS_QTYPE_NUM)
|
||||
stats->qtype[qtype]++;
|
||||
else stats->qtype_big++;
|
||||
if(qclass < STATS_QCLASS_NUM)
|
||||
stats->qclass[qclass]++;
|
||||
else stats->qclass_big++;
|
||||
stats->qopcode[ LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) ]++;
|
||||
if(c->type != comm_udp)
|
||||
stats->qtcp++;
|
||||
if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen))
|
||||
stats->qipv6++;
|
||||
if( (flags&BIT_QR) )
|
||||
stats->qbit_QR++;
|
||||
if( (flags&BIT_AA) )
|
||||
stats->qbit_AA++;
|
||||
if( (flags&BIT_TC) )
|
||||
stats->qbit_TC++;
|
||||
if( (flags&BIT_RD) )
|
||||
stats->qbit_RD++;
|
||||
if( (flags&BIT_RA) )
|
||||
stats->qbit_RA++;
|
||||
if( (flags&BIT_Z) )
|
||||
stats->qbit_Z++;
|
||||
if( (flags&BIT_AD) )
|
||||
stats->qbit_AD++;
|
||||
if( (flags&BIT_CD) )
|
||||
stats->qbit_CD++;
|
||||
if(edns->edns_present) {
|
||||
stats->qEDNS++;
|
||||
if( (edns->bits & EDNS_DO) )
|
||||
stats->qEDNS_DO++;
|
||||
}
|
||||
}
|
||||
|
||||
void server_stats_insrcode(struct server_stats* stats, ldns_buffer* buf)
|
||||
{
|
||||
if(stats->extended && ldns_buffer_limit(buf) != 0) {
|
||||
int r = (int)LDNS_RCODE_WIRE( ldns_buffer_begin(buf) );
|
||||
stats->ans_rcode[r] ++;
|
||||
if(r == 0 && LDNS_ANCOUNT( ldns_buffer_begin(buf) ) == 0)
|
||||
stats->ans_rcode_nodata ++;
|
||||
}
|
||||
}
|
235
contrib/unbound/daemon/stats.h
Normal file
235
contrib/unbound/daemon/stats.h
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* daemon/stats.h - collect runtime performance indicators.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file describes the data structure used to collect runtime performance
|
||||
* numbers. These 'statistics' may be of interest to the operator.
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_STATS_H
|
||||
#define DAEMON_STATS_H
|
||||
#include "util/timehist.h"
|
||||
#include <ldns/buffer.h>
|
||||
struct worker;
|
||||
struct config_file;
|
||||
struct comm_point;
|
||||
struct comm_reply;
|
||||
struct edns_data;
|
||||
|
||||
/** number of qtype that is stored for in array */
|
||||
#define STATS_QTYPE_NUM 256
|
||||
/** number of qclass that is stored for in array */
|
||||
#define STATS_QCLASS_NUM 256
|
||||
/** number of rcodes in stats */
|
||||
#define STATS_RCODE_NUM 16
|
||||
/** number of opcodes in stats */
|
||||
#define STATS_OPCODE_NUM 16
|
||||
|
||||
/** per worker statistics */
|
||||
struct server_stats {
|
||||
/** number of queries from clients received. */
|
||||
size_t num_queries;
|
||||
/** number of queries that had a cache-miss. */
|
||||
size_t num_queries_missed_cache;
|
||||
/** number of prefetch queries - cachehits with prefetch */
|
||||
size_t num_queries_prefetch;
|
||||
|
||||
/**
|
||||
* Sum of the querylistsize of the worker for
|
||||
* every query that missed cache. To calculate average.
|
||||
*/
|
||||
size_t sum_query_list_size;
|
||||
/** max value of query list size reached. */
|
||||
size_t max_query_list_size;
|
||||
|
||||
/** Extended stats below (bool) */
|
||||
int extended;
|
||||
|
||||
/** qtype stats */
|
||||
size_t qtype[STATS_QTYPE_NUM];
|
||||
/** bigger qtype values not in array */
|
||||
size_t qtype_big;
|
||||
/** qclass stats */
|
||||
size_t qclass[STATS_QCLASS_NUM];
|
||||
/** bigger qclass values not in array */
|
||||
size_t qclass_big;
|
||||
/** query opcodes */
|
||||
size_t qopcode[STATS_OPCODE_NUM];
|
||||
/** number of queries over TCP */
|
||||
size_t qtcp;
|
||||
/** number of queries over IPv6 */
|
||||
size_t qipv6;
|
||||
/** number of queries with QR bit */
|
||||
size_t qbit_QR;
|
||||
/** number of queries with AA bit */
|
||||
size_t qbit_AA;
|
||||
/** number of queries with TC bit */
|
||||
size_t qbit_TC;
|
||||
/** number of queries with RD bit */
|
||||
size_t qbit_RD;
|
||||
/** number of queries with RA bit */
|
||||
size_t qbit_RA;
|
||||
/** number of queries with Z bit */
|
||||
size_t qbit_Z;
|
||||
/** number of queries with AD bit */
|
||||
size_t qbit_AD;
|
||||
/** number of queries with CD bit */
|
||||
size_t qbit_CD;
|
||||
/** number of queries with EDNS OPT record */
|
||||
size_t qEDNS;
|
||||
/** number of queries with EDNS with DO flag */
|
||||
size_t qEDNS_DO;
|
||||
/** answer rcodes */
|
||||
size_t ans_rcode[STATS_RCODE_NUM];
|
||||
/** answers with pseudo rcode 'nodata' */
|
||||
size_t ans_rcode_nodata;
|
||||
/** answers that were secure (AD) */
|
||||
size_t ans_secure;
|
||||
/** answers that were bogus (withheld as SERVFAIL) */
|
||||
size_t ans_bogus;
|
||||
/** rrsets marked bogus by validator */
|
||||
size_t rrset_bogus;
|
||||
/** unwanted traffic received on server-facing ports */
|
||||
size_t unwanted_replies;
|
||||
/** unwanted traffic received on client-facing ports */
|
||||
size_t unwanted_queries;
|
||||
|
||||
/** histogram data exported to array
|
||||
* if the array is the same size, no data is lost, and
|
||||
* if all histograms are same size (is so by default) then
|
||||
* adding up works well. */
|
||||
size_t hist[NUM_BUCKETS_HIST];
|
||||
};
|
||||
|
||||
/**
|
||||
* Statistics to send over the control pipe when asked
|
||||
* This struct is made to be memcpied, sent in binary.
|
||||
*/
|
||||
struct stats_info {
|
||||
/** the thread stats */
|
||||
struct server_stats svr;
|
||||
|
||||
/** mesh stats: current number of states */
|
||||
size_t mesh_num_states;
|
||||
/** mesh stats: current number of reply (user) states */
|
||||
size_t mesh_num_reply_states;
|
||||
/** mesh stats: number of reply states overwritten with a new one */
|
||||
size_t mesh_jostled;
|
||||
/** mesh stats: number of incoming queries dropped */
|
||||
size_t mesh_dropped;
|
||||
/** mesh stats: replies sent */
|
||||
size_t mesh_replies_sent;
|
||||
/** mesh stats: sum of waiting times for the replies */
|
||||
struct timeval mesh_replies_sum_wait;
|
||||
/** mesh stats: median of waiting times for replies (in sec) */
|
||||
double mesh_time_median;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize server stats to 0.
|
||||
* @param stats: what to init (this is alloced by the caller).
|
||||
* @param cfg: with extended statistics option.
|
||||
*/
|
||||
void server_stats_init(struct server_stats* stats, struct config_file* cfg);
|
||||
|
||||
/** add query if it missed the cache */
|
||||
void server_stats_querymiss(struct server_stats* stats, struct worker* worker);
|
||||
|
||||
/** add query if was cached and also resulted in a prefetch */
|
||||
void server_stats_prefetch(struct server_stats* stats, struct worker* worker);
|
||||
|
||||
/** display the stats to the log */
|
||||
void server_stats_log(struct server_stats* stats, struct worker* worker,
|
||||
int threadnum);
|
||||
|
||||
/**
|
||||
* Obtain the stats info for a given thread. Uses pipe to communicate.
|
||||
* @param worker: the worker that is executing (the first worker).
|
||||
* @param who: on who to get the statistics info.
|
||||
* @param s: the stats block to fill in.
|
||||
* @param reset: if stats can be reset.
|
||||
*/
|
||||
void server_stats_obtain(struct worker* worker, struct worker* who,
|
||||
struct stats_info* s, int reset);
|
||||
|
||||
/**
|
||||
* Compile stats into structure for this thread worker.
|
||||
* Also clears the statistics counters (if that is set by config file).
|
||||
* @param worker: the worker to compile stats for, also the executing worker.
|
||||
* @param s: stats block.
|
||||
* @param reset: if true, depending on config stats are reset.
|
||||
* if false, statistics are not reset.
|
||||
*/
|
||||
void server_stats_compile(struct worker* worker, struct stats_info* s,
|
||||
int reset);
|
||||
|
||||
/**
|
||||
* Send stats over comm tube in reply to query cmd
|
||||
* @param worker: this worker.
|
||||
* @param reset: if true, depending on config stats are reset.
|
||||
* if false, statistics are not reset.
|
||||
*/
|
||||
void server_stats_reply(struct worker* worker, int reset);
|
||||
|
||||
/**
|
||||
* Addup stat blocks.
|
||||
* @param total: sum of the two entries.
|
||||
* @param a: to add to it.
|
||||
*/
|
||||
void server_stats_add(struct stats_info* total, struct stats_info* a);
|
||||
|
||||
/**
|
||||
* Add stats for this query
|
||||
* @param stats: the stats
|
||||
* @param c: commpoint with type and buffer.
|
||||
* @param qtype: query type
|
||||
* @param qclass: query class
|
||||
* @param edns: edns record
|
||||
* @param repinfo: reply info with remote address
|
||||
*/
|
||||
void server_stats_insquery(struct server_stats* stats, struct comm_point* c,
|
||||
uint16_t qtype, uint16_t qclass, struct edns_data* edns,
|
||||
struct comm_reply* repinfo);
|
||||
|
||||
/**
|
||||
* Add rcode for this query.
|
||||
* @param stats: the stats
|
||||
* @param buf: buffer with rcode. If buffer is length0: not counted.
|
||||
*/
|
||||
void server_stats_insrcode(struct server_stats* stats, ldns_buffer* buf);
|
||||
|
||||
#endif /* DAEMON_STATS_H */
|
748
contrib/unbound/daemon/unbound.c
Normal file
748
contrib/unbound/daemon/unbound.c
Normal file
@ -0,0 +1,748 @@
|
||||
/*
|
||||
* daemon/unbound.c - main program for unbound DNS resolver daemon.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* Main program to start the DNS resolver daemon.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include "util/log.h"
|
||||
#include "daemon/daemon.h"
|
||||
#include "daemon/remote.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/module.h"
|
||||
#include "util/net_help.h"
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <openssl/crypto.h>
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GRP_H
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#ifdef HAVE_LOGIN_CAP_H
|
||||
#include <login_cap.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_MINI_EVENT
|
||||
# ifdef USE_WINSOCK
|
||||
# include "util/winsock_event.h"
|
||||
# else
|
||||
# include "util/mini_event.h"
|
||||
# endif
|
||||
#else
|
||||
# include <event.h>
|
||||
#endif
|
||||
|
||||
#ifdef UB_ON_WINDOWS
|
||||
# include "winrc/win_svc.h"
|
||||
#endif
|
||||
|
||||
/** global debug value to keep track of heap memory allocation */
|
||||
void* unbound_start_brk = 0;
|
||||
|
||||
#if !defined(HAVE_EVENT_BASE_GET_METHOD) && (defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP))
|
||||
static const char* ev_backend2str(int b)
|
||||
{
|
||||
switch(b) {
|
||||
case EVBACKEND_SELECT: return "select";
|
||||
case EVBACKEND_POLL: return "poll";
|
||||
case EVBACKEND_EPOLL: return "epoll";
|
||||
case EVBACKEND_KQUEUE: return "kqueue";
|
||||
case EVBACKEND_DEVPOLL: return "devpoll";
|
||||
case EVBACKEND_PORT: return "evport";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
#endif
|
||||
|
||||
/** get the event system in use */
|
||||
static void get_event_sys(const char** n, const char** s, const char** m)
|
||||
{
|
||||
#ifdef USE_WINSOCK
|
||||
*n = "event";
|
||||
*s = "winsock";
|
||||
*m = "WSAWaitForMultipleEvents";
|
||||
#elif defined(USE_MINI_EVENT)
|
||||
*n = "mini-event";
|
||||
*s = "internal";
|
||||
*m = "select";
|
||||
#else
|
||||
struct event_base* b;
|
||||
*s = event_get_version();
|
||||
# ifdef HAVE_EVENT_BASE_GET_METHOD
|
||||
*n = "libevent";
|
||||
b = event_base_new();
|
||||
*m = event_base_get_method(b);
|
||||
# elif defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
|
||||
*n = "libev";
|
||||
b = (struct event_base*)ev_default_loop(EVFLAG_AUTO);
|
||||
*m = ev_backend2str(ev_backend((struct ev_loop*)b));
|
||||
# else
|
||||
*n = "unknown";
|
||||
*m = "not obtainable";
|
||||
b = NULL;
|
||||
# endif
|
||||
# ifdef HAVE_EVENT_BASE_FREE
|
||||
event_base_free(b);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/** print usage. */
|
||||
static void usage()
|
||||
{
|
||||
const char** m;
|
||||
const char *evnm="event", *evsys="", *evmethod="";
|
||||
printf("usage: unbound [options]\n");
|
||||
printf(" start unbound daemon DNS resolver.\n");
|
||||
printf("-h this help\n");
|
||||
printf("-c file config file to read instead of %s\n", CONFIGFILE);
|
||||
printf(" file format is described in unbound.conf(5).\n");
|
||||
printf("-d do not fork into the background.\n");
|
||||
printf("-v verbose (more times to increase verbosity)\n");
|
||||
#ifdef UB_ON_WINDOWS
|
||||
printf("-w opt windows option: \n");
|
||||
printf(" install, remove - manage the services entry\n");
|
||||
printf(" service - used to start from services control panel\n");
|
||||
#endif
|
||||
printf("Version %s\n", PACKAGE_VERSION);
|
||||
get_event_sys(&evnm, &evsys, &evmethod);
|
||||
printf("linked libs: %s %s (it uses %s), ldns %s, %s\n",
|
||||
evnm, evsys, evmethod, ldns_version(),
|
||||
SSLeay_version(SSLEAY_VERSION));
|
||||
printf("linked modules:");
|
||||
for(m = module_list_avail(); *m; m++)
|
||||
printf(" %s", *m);
|
||||
printf("\n");
|
||||
printf("configured for %s on %s with options:%s\n",
|
||||
CONFIGURE_TARGET, CONFIGURE_DATE, CONFIGURE_BUILD_WITH);
|
||||
printf("BSD licensed, see LICENSE in source package for details.\n");
|
||||
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
|
||||
}
|
||||
|
||||
#ifndef unbound_testbound
|
||||
int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** check file descriptor count */
|
||||
static void
|
||||
checkrlimits(struct config_file* cfg)
|
||||
{
|
||||
#ifdef HAVE_GETRLIMIT
|
||||
/* list has number of ports to listen to, ifs number addresses */
|
||||
int list = ((cfg->do_udp?1:0) + (cfg->do_tcp?1 +
|
||||
(int)cfg->incoming_num_tcp:0));
|
||||
size_t listen_ifs = (size_t)(cfg->num_ifs==0?
|
||||
((cfg->do_ip4 && !cfg->if_automatic?1:0) +
|
||||
(cfg->do_ip6?1:0)):cfg->num_ifs);
|
||||
size_t listen_num = list*listen_ifs;
|
||||
size_t outudpnum = (size_t)cfg->outgoing_num_ports;
|
||||
size_t outtcpnum = cfg->outgoing_num_tcp;
|
||||
size_t misc = 4; /* logfile, pidfile, stdout... */
|
||||
size_t perthread_noudp = listen_num + outtcpnum +
|
||||
2/*cmdpipe*/ + 2/*libevent*/ + misc;
|
||||
size_t perthread = perthread_noudp + outudpnum;
|
||||
|
||||
#if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS)
|
||||
int numthread = 1; /* it forks */
|
||||
#else
|
||||
int numthread = (cfg->num_threads?cfg->num_threads:1);
|
||||
#endif
|
||||
size_t total = numthread * perthread + misc;
|
||||
size_t avail;
|
||||
struct rlimit rlim;
|
||||
|
||||
if(total > 1024 &&
|
||||
strncmp(event_get_version(), "mini-event", 10) == 0) {
|
||||
log_warn("too many file descriptors requested. The builtin"
|
||||
"mini-event cannot handle more than 1024. Config "
|
||||
"for less fds or compile with libevent");
|
||||
if(numthread*perthread_noudp+15 > 1024)
|
||||
fatal_exit("too much tcp. not enough fds.");
|
||||
cfg->outgoing_num_ports = (int)((1024
|
||||
- numthread*perthread_noudp
|
||||
- 10 /* safety margin */) /numthread);
|
||||
log_warn("continuing with less udp ports: %u",
|
||||
cfg->outgoing_num_ports);
|
||||
total = 1024;
|
||||
}
|
||||
if(perthread > 64 &&
|
||||
strncmp(event_get_version(), "winsock-event", 13) == 0) {
|
||||
log_err("too many file descriptors requested. The winsock"
|
||||
" event handler cannot handle more than 64 per "
|
||||
" thread. Config for less fds");
|
||||
if(perthread_noudp+2 > 64)
|
||||
fatal_exit("too much tcp. not enough fds.");
|
||||
cfg->outgoing_num_ports = (int)((64
|
||||
- perthread_noudp
|
||||
- 2/* safety margin */));
|
||||
log_warn("continuing with less udp ports: %u",
|
||||
cfg->outgoing_num_ports);
|
||||
total = numthread*(perthread_noudp+
|
||||
(size_t)cfg->outgoing_num_ports)+misc;
|
||||
}
|
||||
if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
||||
log_warn("getrlimit: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
if(rlim.rlim_cur == (rlim_t)RLIM_INFINITY)
|
||||
return;
|
||||
if((size_t)rlim.rlim_cur < total) {
|
||||
avail = (size_t)rlim.rlim_cur;
|
||||
rlim.rlim_cur = (rlim_t)(total + 10);
|
||||
rlim.rlim_max = (rlim_t)(total + 10);
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
||||
log_warn("setrlimit: %s", strerror(errno));
|
||||
#else
|
||||
if(1) {
|
||||
#endif
|
||||
log_warn("cannot increase max open fds from %u to %u",
|
||||
(unsigned)avail, (unsigned)total+10);
|
||||
/* check that calculation below does not underflow,
|
||||
* with 15 as margin */
|
||||
if(numthread*perthread_noudp+15 > avail)
|
||||
fatal_exit("too much tcp. not enough fds.");
|
||||
cfg->outgoing_num_ports = (int)((avail
|
||||
- numthread*perthread_noudp
|
||||
- 10 /* safety margin */) /numthread);
|
||||
log_warn("continuing with less udp ports: %u",
|
||||
cfg->outgoing_num_ports);
|
||||
log_warn("increase ulimit or decrease threads, "
|
||||
"ports in config to remove this warning");
|
||||
return;
|
||||
}
|
||||
log_warn("increased limit(open files) from %u to %u",
|
||||
(unsigned)avail, (unsigned)total+10);
|
||||
}
|
||||
#else
|
||||
(void)cfg;
|
||||
#endif /* HAVE_GETRLIMIT */
|
||||
}
|
||||
|
||||
/** set verbosity, check rlimits, cache settings */
|
||||
static void
|
||||
apply_settings(struct daemon* daemon, struct config_file* cfg,
|
||||
int cmdline_verbose)
|
||||
{
|
||||
/* apply if they have changed */
|
||||
verbosity = cmdline_verbose + cfg->verbosity;
|
||||
daemon_apply_cfg(daemon, cfg);
|
||||
checkrlimits(cfg);
|
||||
}
|
||||
|
||||
#ifdef HAVE_KILL
|
||||
/** Read existing pid from pidfile.
|
||||
* @param file: file name of pid file.
|
||||
* @return: the pid from the file or -1 if none.
|
||||
*/
|
||||
static pid_t
|
||||
readpid (const char* file)
|
||||
{
|
||||
int fd;
|
||||
pid_t pid;
|
||||
char pidbuf[32];
|
||||
char* t;
|
||||
ssize_t l;
|
||||
|
||||
if ((fd = open(file, O_RDONLY)) == -1) {
|
||||
if(errno != ENOENT)
|
||||
log_err("Could not read pidfile %s: %s",
|
||||
file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) {
|
||||
if(errno != ENOENT)
|
||||
log_err("Could not read pidfile %s: %s",
|
||||
file, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* Empty pidfile means no pidfile... */
|
||||
if (l == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pidbuf[sizeof(pidbuf)-1] = 0;
|
||||
pid = (pid_t)strtol(pidbuf, &t, 10);
|
||||
|
||||
if (*t && *t != '\n') {
|
||||
return -1;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
/** write pid to file.
|
||||
* @param pidfile: file name of pid file.
|
||||
* @param pid: pid to write to file.
|
||||
*/
|
||||
static void
|
||||
writepid (const char* pidfile, pid_t pid)
|
||||
{
|
||||
FILE* f;
|
||||
|
||||
if ((f = fopen(pidfile, "w")) == NULL ) {
|
||||
log_err("cannot open pidfile %s: %s",
|
||||
pidfile, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if(fprintf(f, "%lu\n", (unsigned long)pid) < 0) {
|
||||
log_err("cannot write to pidfile %s: %s",
|
||||
pidfile, strerror(errno));
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* check old pid file.
|
||||
* @param pidfile: the file name of the pid file.
|
||||
* @param inchroot: if pidfile is inchroot and we can thus expect to
|
||||
* be able to delete it.
|
||||
*/
|
||||
static void
|
||||
checkoldpid(char* pidfile, int inchroot)
|
||||
{
|
||||
pid_t old;
|
||||
if((old = readpid(pidfile)) != -1) {
|
||||
/* see if it is still alive */
|
||||
if(kill(old, 0) == 0 || errno == EPERM)
|
||||
log_warn("unbound is already running as pid %u.",
|
||||
(unsigned)old);
|
||||
else if(inchroot)
|
||||
log_warn("did not exit gracefully last time (%u)",
|
||||
(unsigned)old);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_KILL */
|
||||
|
||||
/** detach from command line */
|
||||
static void
|
||||
detach(void)
|
||||
{
|
||||
#if defined(HAVE_DAEMON) && !defined(DEPRECATED_DAEMON)
|
||||
/* use POSIX daemon(3) function */
|
||||
if(daemon(1, 0) != 0)
|
||||
fatal_exit("daemon failed: %s", strerror(errno));
|
||||
#else /* no HAVE_DAEMON */
|
||||
#ifdef HAVE_FORK
|
||||
int fd;
|
||||
/* Take off... */
|
||||
switch (fork()) {
|
||||
case 0:
|
||||
break;
|
||||
case -1:
|
||||
fatal_exit("fork failed: %s", strerror(errno));
|
||||
default:
|
||||
/* exit interactive session */
|
||||
exit(0);
|
||||
}
|
||||
/* detach */
|
||||
#ifdef HAVE_SETSID
|
||||
if(setsid() == -1)
|
||||
fatal_exit("setsid() failed: %s", strerror(errno));
|
||||
#endif
|
||||
if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
|
||||
(void)dup2(fd, STDIN_FILENO);
|
||||
(void)dup2(fd, STDOUT_FILENO);
|
||||
(void)dup2(fd, STDERR_FILENO);
|
||||
if (fd > 2)
|
||||
(void)close(fd);
|
||||
}
|
||||
#endif /* HAVE_FORK */
|
||||
#endif /* HAVE_DAEMON */
|
||||
}
|
||||
|
||||
/** daemonize, drop user priviliges and chroot if needed */
|
||||
static void
|
||||
perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
||||
const char** cfgfile)
|
||||
{
|
||||
#ifdef HAVE_GETPWNAM
|
||||
struct passwd *pwd = NULL;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
/* initialize, but not to 0 (root) */
|
||||
memset(&uid, 112, sizeof(uid));
|
||||
memset(&gid, 112, sizeof(gid));
|
||||
log_assert(cfg);
|
||||
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
if((pwd = getpwnam(cfg->username)) == NULL)
|
||||
fatal_exit("user '%s' does not exist.", cfg->username);
|
||||
uid = pwd->pw_uid;
|
||||
gid = pwd->pw_gid;
|
||||
/* endpwent below, in case we need pwd for setusercontext */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* init syslog (as root) if needed, before daemonize, otherwise
|
||||
* a fork error could not be printed since daemonize closed stderr.*/
|
||||
if(cfg->use_syslog) {
|
||||
log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
|
||||
}
|
||||
/* if using a logfile, we cannot open it because the logfile would
|
||||
* be created with the wrong permissions, we cannot chown it because
|
||||
* we cannot chown system logfiles, so we do not open at all.
|
||||
* So, using a logfile, the user does not see errors unless -d is
|
||||
* given to unbound on the commandline. */
|
||||
|
||||
/* read ssl keys while superuser and outside chroot */
|
||||
if(!(daemon->rc = daemon_remote_create(cfg)))
|
||||
fatal_exit("could not set up remote-control");
|
||||
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
|
||||
if(!(daemon->listen_sslctx = listen_sslctx_create(
|
||||
cfg->ssl_service_key, cfg->ssl_service_pem, NULL)))
|
||||
fatal_exit("could not set up listen SSL_CTX");
|
||||
}
|
||||
if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, NULL)))
|
||||
fatal_exit("could not set up connect SSL_CTX");
|
||||
|
||||
#ifdef HAVE_KILL
|
||||
/* check old pid file before forking */
|
||||
if(cfg->pidfile && cfg->pidfile[0]) {
|
||||
/* calculate position of pidfile */
|
||||
if(cfg->pidfile[0] == '/')
|
||||
daemon->pidfile = strdup(cfg->pidfile);
|
||||
else daemon->pidfile = fname_after_chroot(cfg->pidfile,
|
||||
cfg, 1);
|
||||
if(!daemon->pidfile)
|
||||
fatal_exit("pidfile alloc: out of memory");
|
||||
checkoldpid(daemon->pidfile,
|
||||
/* true if pidfile is inside chrootdir, or nochroot */
|
||||
!(cfg->chrootdir && cfg->chrootdir[0]) ||
|
||||
(cfg->chrootdir && cfg->chrootdir[0] &&
|
||||
strncmp(daemon->pidfile, cfg->chrootdir,
|
||||
strlen(cfg->chrootdir))==0));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* daemonize because pid is needed by the writepid func */
|
||||
if(!debug_mode && cfg->do_daemonize) {
|
||||
detach();
|
||||
}
|
||||
|
||||
/* write new pidfile (while still root, so can be outside chroot) */
|
||||
#ifdef HAVE_KILL
|
||||
if(cfg->pidfile && cfg->pidfile[0]) {
|
||||
writepid(daemon->pidfile, getpid());
|
||||
if(!(cfg->chrootdir && cfg->chrootdir[0]) ||
|
||||
(cfg->chrootdir && cfg->chrootdir[0] &&
|
||||
strncmp(daemon->pidfile, cfg->chrootdir,
|
||||
strlen(cfg->chrootdir))==0)) {
|
||||
/* delete of pidfile could potentially work,
|
||||
* chown to get permissions */
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
if(chown(daemon->pidfile, uid, gid) == -1) {
|
||||
log_err("cannot chown %u.%u %s: %s",
|
||||
(unsigned)uid, (unsigned)gid,
|
||||
daemon->pidfile, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)daemon;
|
||||
#endif
|
||||
|
||||
/* Set user context */
|
||||
#ifdef HAVE_GETPWNAM
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
#ifdef HAVE_SETUSERCONTEXT
|
||||
/* setusercontext does initgroups, setuid, setgid, and
|
||||
* also resource limits from login config, but we
|
||||
* still call setresuid, setresgid to be sure to set all uid*/
|
||||
if(setusercontext(NULL, pwd, uid,
|
||||
LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0)
|
||||
log_warn("unable to setusercontext %s: %s",
|
||||
cfg->username, strerror(errno));
|
||||
#endif /* HAVE_SETUSERCONTEXT */
|
||||
}
|
||||
#endif /* HAVE_GETPWNAM */
|
||||
|
||||
/* box into the chroot */
|
||||
#ifdef HAVE_CHROOT
|
||||
if(cfg->chrootdir && cfg->chrootdir[0]) {
|
||||
if(chdir(cfg->chrootdir)) {
|
||||
fatal_exit("unable to chdir to chroot %s: %s",
|
||||
cfg->chrootdir, strerror(errno));
|
||||
}
|
||||
verbose(VERB_QUERY, "chdir to %s", cfg->chrootdir);
|
||||
if(chroot(cfg->chrootdir))
|
||||
fatal_exit("unable to chroot to %s: %s",
|
||||
cfg->chrootdir, strerror(errno));
|
||||
verbose(VERB_QUERY, "chroot to %s", cfg->chrootdir);
|
||||
if(strncmp(*cfgfile, cfg->chrootdir,
|
||||
strlen(cfg->chrootdir)) == 0)
|
||||
(*cfgfile) += strlen(cfg->chrootdir);
|
||||
|
||||
/* adjust stored pidfile for chroot */
|
||||
if(daemon->pidfile && daemon->pidfile[0] &&
|
||||
strncmp(daemon->pidfile, cfg->chrootdir,
|
||||
strlen(cfg->chrootdir))==0) {
|
||||
char* old = daemon->pidfile;
|
||||
daemon->pidfile = strdup(old+strlen(cfg->chrootdir));
|
||||
free(old);
|
||||
if(!daemon->pidfile)
|
||||
log_err("out of memory in pidfile adjust");
|
||||
}
|
||||
daemon->chroot = strdup(cfg->chrootdir);
|
||||
if(!daemon->chroot)
|
||||
log_err("out of memory in daemon chroot dir storage");
|
||||
}
|
||||
#else
|
||||
(void)cfgfile;
|
||||
#endif
|
||||
/* change to working directory inside chroot */
|
||||
if(cfg->directory && cfg->directory[0]) {
|
||||
char* dir = cfg->directory;
|
||||
if(cfg->chrootdir && cfg->chrootdir[0] &&
|
||||
strncmp(dir, cfg->chrootdir,
|
||||
strlen(cfg->chrootdir)) == 0)
|
||||
dir += strlen(cfg->chrootdir);
|
||||
if(dir[0]) {
|
||||
if(chdir(dir)) {
|
||||
fatal_exit("Could not chdir to %s: %s",
|
||||
dir, strerror(errno));
|
||||
}
|
||||
verbose(VERB_QUERY, "chdir to %s", dir);
|
||||
}
|
||||
}
|
||||
|
||||
/* drop permissions after chroot, getpwnam, pidfile, syslog done*/
|
||||
#ifdef HAVE_GETPWNAM
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
# ifdef HAVE_INITGROUPS
|
||||
if(initgroups(cfg->username, gid) != 0)
|
||||
log_warn("unable to initgroups %s: %s",
|
||||
cfg->username, strerror(errno));
|
||||
# endif /* HAVE_INITGROUPS */
|
||||
endpwent();
|
||||
|
||||
#ifdef HAVE_SETRESGID
|
||||
if(setresgid(gid,gid,gid) != 0)
|
||||
#elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID)
|
||||
if(setregid(gid,gid) != 0)
|
||||
#else /* use setgid */
|
||||
if(setgid(gid) != 0)
|
||||
#endif /* HAVE_SETRESGID */
|
||||
fatal_exit("unable to set group id of %s: %s",
|
||||
cfg->username, strerror(errno));
|
||||
#ifdef HAVE_SETRESUID
|
||||
if(setresuid(uid,uid,uid) != 0)
|
||||
#elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID)
|
||||
if(setreuid(uid,uid) != 0)
|
||||
#else /* use setuid */
|
||||
if(setuid(uid) != 0)
|
||||
#endif /* HAVE_SETRESUID */
|
||||
fatal_exit("unable to set user id of %s: %s",
|
||||
cfg->username, strerror(errno));
|
||||
verbose(VERB_QUERY, "drop user privileges, run as %s",
|
||||
cfg->username);
|
||||
}
|
||||
#endif /* HAVE_GETPWNAM */
|
||||
/* file logging inited after chroot,chdir,setuid is done so that
|
||||
* it would succeed on SIGHUP as well */
|
||||
if(!cfg->use_syslog)
|
||||
log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the daemon.
|
||||
* @param cfgfile: the config file name.
|
||||
* @param cmdline_verbose: verbosity resulting from commandline -v.
|
||||
* These increase verbosity as specified in the config file.
|
||||
* @param debug_mode: if set, do not daemonize.
|
||||
*/
|
||||
static void
|
||||
run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode)
|
||||
{
|
||||
struct config_file* cfg = NULL;
|
||||
struct daemon* daemon = NULL;
|
||||
int done_setup = 0;
|
||||
|
||||
if(!(daemon = daemon_init()))
|
||||
fatal_exit("alloc failure");
|
||||
while(!daemon->need_to_exit) {
|
||||
if(done_setup)
|
||||
verbose(VERB_OPS, "Restart of %s.", PACKAGE_STRING);
|
||||
else verbose(VERB_OPS, "Start of %s.", PACKAGE_STRING);
|
||||
|
||||
/* config stuff */
|
||||
if(!(cfg = config_create()))
|
||||
fatal_exit("Could not alloc config defaults");
|
||||
if(!config_read(cfg, cfgfile, daemon->chroot)) {
|
||||
if(errno != ENOENT)
|
||||
fatal_exit("Could not read config file: %s",
|
||||
cfgfile);
|
||||
log_warn("Continuing with default config settings");
|
||||
}
|
||||
apply_settings(daemon, cfg, cmdline_verbose);
|
||||
|
||||
/* prepare */
|
||||
if(!daemon_open_shared_ports(daemon))
|
||||
fatal_exit("could not open ports");
|
||||
if(!done_setup) {
|
||||
perform_setup(daemon, cfg, debug_mode, &cfgfile);
|
||||
done_setup = 1;
|
||||
} else {
|
||||
/* reopen log after HUP to facilitate log rotation */
|
||||
if(!cfg->use_syslog)
|
||||
log_init(cfg->logfile, 0, cfg->chrootdir);
|
||||
}
|
||||
/* work */
|
||||
daemon_fork(daemon);
|
||||
|
||||
/* clean up for restart */
|
||||
verbose(VERB_ALGO, "cleanup.");
|
||||
daemon_cleanup(daemon);
|
||||
config_delete(cfg);
|
||||
}
|
||||
verbose(VERB_ALGO, "Exit cleanup.");
|
||||
/* this unlink may not work if the pidfile is located outside
|
||||
* of the chroot/workdir or we no longer have permissions */
|
||||
if(daemon->pidfile) {
|
||||
int fd;
|
||||
/* truncate pidfile */
|
||||
fd = open(daemon->pidfile, O_WRONLY | O_TRUNC, 0644);
|
||||
if(fd != -1)
|
||||
close(fd);
|
||||
/* delete pidfile */
|
||||
unlink(daemon->pidfile);
|
||||
}
|
||||
daemon_delete(daemon);
|
||||
}
|
||||
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern int optind;
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern char* optarg;
|
||||
|
||||
/**
|
||||
* main program. Set options given commandline arguments.
|
||||
* @param argc: number of commandline arguments.
|
||||
* @param argv: array of commandline arguments.
|
||||
* @return: exit status of the program.
|
||||
*/
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int c;
|
||||
const char* cfgfile = CONFIGFILE;
|
||||
const char* winopt = NULL;
|
||||
int cmdline_verbose = 0;
|
||||
int debug_mode = 0;
|
||||
#ifdef UB_ON_WINDOWS
|
||||
int cmdline_cfg = 0;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SBRK
|
||||
/* take debug snapshot of heap */
|
||||
unbound_start_brk = sbrk(0);
|
||||
#endif
|
||||
|
||||
log_init(NULL, 0, NULL);
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "c:dhvw:")) != -1) {
|
||||
switch(c) {
|
||||
case 'c':
|
||||
cfgfile = optarg;
|
||||
#ifdef UB_ON_WINDOWS
|
||||
cmdline_cfg = 1;
|
||||
#endif
|
||||
break;
|
||||
case 'v':
|
||||
cmdline_verbose ++;
|
||||
verbosity++;
|
||||
break;
|
||||
case 'd':
|
||||
debug_mode = 1;
|
||||
break;
|
||||
case 'w':
|
||||
winopt = optarg;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(winopt) {
|
||||
#ifdef UB_ON_WINDOWS
|
||||
wsvc_command_option(winopt, cfgfile, cmdline_verbose,
|
||||
cmdline_cfg);
|
||||
#else
|
||||
fatal_exit("option not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
if(argc != 0) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
run_daemon(cfgfile, cmdline_verbose, debug_mode);
|
||||
log_init(NULL, 0, NULL); /* close logfile */
|
||||
return 0;
|
||||
}
|
1377
contrib/unbound/daemon/worker.c
Normal file
1377
contrib/unbound/daemon/worker.c
Normal file
File diff suppressed because it is too large
Load Diff
234
contrib/unbound/daemon/worker.h
Normal file
234
contrib/unbound/daemon/worker.h
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* daemon/worker.h - worker that handles a pending list of requests.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file describes the worker structure that holds a list of
|
||||
* pending requests and handles them.
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_WORKER_H
|
||||
#define DAEMON_WORKER_H
|
||||
|
||||
#include "util/netevent.h"
|
||||
#include "util/locks.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "daemon/stats.h"
|
||||
#include "util/module.h"
|
||||
struct listen_dnsport;
|
||||
struct outside_network;
|
||||
struct config_file;
|
||||
struct daemon;
|
||||
struct listen_port;
|
||||
struct ub_randstate;
|
||||
struct regional;
|
||||
struct tube;
|
||||
struct daemon_remote;
|
||||
|
||||
/** worker commands */
|
||||
enum worker_commands {
|
||||
/** make the worker quit */
|
||||
worker_cmd_quit,
|
||||
/** obtain statistics */
|
||||
worker_cmd_stats,
|
||||
/** obtain statistics without statsclear */
|
||||
worker_cmd_stats_noreset,
|
||||
/** execute remote control command */
|
||||
worker_cmd_remote
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure holding working information for unbound.
|
||||
* Holds globally visible information.
|
||||
*/
|
||||
struct worker {
|
||||
/** the thread number (in daemon array). First in struct for debug. */
|
||||
int thread_num;
|
||||
/** global shared daemon structure */
|
||||
struct daemon* daemon;
|
||||
/** thread id */
|
||||
ub_thread_t thr_id;
|
||||
/** pipe, for commands for this worker */
|
||||
struct tube* cmd;
|
||||
/** the event base this worker works with */
|
||||
struct comm_base* base;
|
||||
/** the frontside listening interface where request events come in */
|
||||
struct listen_dnsport* front;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** ports to be used by this worker. */
|
||||
int* ports;
|
||||
/** number of ports for this worker */
|
||||
int numports;
|
||||
/** the signal handler */
|
||||
struct comm_signal* comsig;
|
||||
/** commpoint to listen to commands. */
|
||||
struct comm_point* cmd_com;
|
||||
/** timer for statistics */
|
||||
struct comm_timer* stat_timer;
|
||||
|
||||
/** random() table for this worker. */
|
||||
struct ub_randstate* rndstate;
|
||||
/** do we need to restart or quit (on signal) */
|
||||
int need_to_exit;
|
||||
/** allocation cache for this thread */
|
||||
struct alloc_cache alloc;
|
||||
/** per thread statistics */
|
||||
struct server_stats stats;
|
||||
/** thread scratch regional */
|
||||
struct regional* scratchpad;
|
||||
|
||||
/** module environment passed to modules, changed for this thread */
|
||||
struct module_env env;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the worker structure. Bare bones version, zeroed struct,
|
||||
* with backpointers only. Use worker_init on it later.
|
||||
* @param daemon: the daemon that this worker thread is part of.
|
||||
* @param id: the thread number from 0.. numthreads-1.
|
||||
* @param ports: the ports it is allowed to use, array.
|
||||
* @param n: the number of ports.
|
||||
* @return: the new worker or NULL on alloc failure.
|
||||
*/
|
||||
struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n);
|
||||
|
||||
/**
|
||||
* Initialize worker.
|
||||
* Allocates event base, listens to ports
|
||||
* @param worker: worker to initialize, created with worker_create.
|
||||
* @param cfg: configuration settings.
|
||||
* @param ports: list of shared query ports.
|
||||
* @param do_sigs: if true, worker installs signal handlers.
|
||||
* @return: false on error.
|
||||
*/
|
||||
int worker_init(struct worker* worker, struct config_file *cfg,
|
||||
struct listen_port* ports, int do_sigs);
|
||||
|
||||
/**
|
||||
* Make worker work.
|
||||
*/
|
||||
void worker_work(struct worker* worker);
|
||||
|
||||
/**
|
||||
* Delete worker.
|
||||
*/
|
||||
void worker_delete(struct worker* worker);
|
||||
|
||||
/**
|
||||
* Send a command to a worker. Uses blocking writes.
|
||||
* @param worker: worker to send command to.
|
||||
* @param cmd: command to send.
|
||||
*/
|
||||
void worker_send_cmd(struct worker* worker, enum worker_commands cmd);
|
||||
|
||||
/**
|
||||
* Worker signal handler function. User argument is the worker itself.
|
||||
* @param sig: signal number.
|
||||
* @param arg: the worker (main worker) that handles signals.
|
||||
*/
|
||||
void worker_sighandler(int sig, void* arg);
|
||||
|
||||
/**
|
||||
* Worker service routine to send serviced queries to authoritative servers.
|
||||
* @param qname: query name. (host order)
|
||||
* @param qnamelen: length in bytes of qname, including trailing 0.
|
||||
* @param qtype: query type. (host order)
|
||||
* @param qclass: query class. (host order)
|
||||
* @param flags: host order flags word, with opcode and CD bit.
|
||||
* @param dnssec: if set, EDNS record will have DO bit set.
|
||||
* @param want_dnssec: signatures needed.
|
||||
* @param addr: where to.
|
||||
* @param addrlen: length of addr.
|
||||
* @param zone: wireformat dname of the zone.
|
||||
* @param zonelen: length of zone name.
|
||||
* @param q: wich query state to reactivate upon return.
|
||||
* @return: false on failure (memory or socket related). no query was
|
||||
* sent.
|
||||
*/
|
||||
struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen,
|
||||
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
|
||||
int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* zone, size_t zonelen, struct module_qstate* q);
|
||||
|
||||
/**
|
||||
* process control messages from the main thread. Frees the control
|
||||
* command message.
|
||||
* @param tube: tube control message came on.
|
||||
* @param msg: message contents. Is freed.
|
||||
* @param len: length of message.
|
||||
* @param error: if error (NETEVENT_*) happened.
|
||||
* @param arg: user argument
|
||||
*/
|
||||
void worker_handle_control_cmd(struct tube* tube, uint8_t* msg, size_t len,
|
||||
int error, void* arg);
|
||||
|
||||
/** handles callbacks from listening event interface */
|
||||
int worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* repinfo);
|
||||
|
||||
/** process incoming replies from the network */
|
||||
int worker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info);
|
||||
|
||||
/** process incoming serviced query replies from the network */
|
||||
int worker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info);
|
||||
|
||||
/** cleanup the cache to remove all rrset IDs from it, arg is worker */
|
||||
void worker_alloc_cleanup(void* arg);
|
||||
|
||||
/**
|
||||
* Init worker stats - includes server_stats_init, outside network and mesh.
|
||||
* @param worker: the worker to init
|
||||
*/
|
||||
void worker_stats_clear(struct worker* worker);
|
||||
|
||||
/** statistics timer callback handler */
|
||||
void worker_stat_timer_cb(void* arg);
|
||||
|
||||
/** probe timer callback handler */
|
||||
void worker_probe_timer_cb(void* arg);
|
||||
|
||||
/** start accept callback handler */
|
||||
void worker_start_accept(void* arg);
|
||||
|
||||
/** stop accept callback handler */
|
||||
void worker_stop_accept(void* arg);
|
||||
|
||||
#endif /* DAEMON_WORKER_H */
|
21
contrib/unbound/doc/CREDITS
Normal file
21
contrib/unbound/doc/CREDITS
Normal file
@ -0,0 +1,21 @@
|
||||
Unbound was developed at NLnet Labs by Wouter Wijngaards.
|
||||
|
||||
Unbound was architected in January of 2004 by Jakob Schlyter of Kirei
|
||||
and Roy Arends of Nominet. VeriSign and EP.Net funded development of
|
||||
the prototype, which was built by David Blacka and Matt Larson of VeriSign.
|
||||
Late in 2006, NLnet Labs joined the effort, writing an implementation in C
|
||||
based on the existing prototype and using experience NLnet Labs gained
|
||||
during the development of NSD, an authoritative DNS server.
|
||||
|
||||
At NLnet Labs, Jelte Jansen, Mark Santcroos and Matthijs Mekking
|
||||
reviewed the unbound C sources.
|
||||
|
||||
Jakob Schlyter - for advice on secure settings, random numbers and blacklists.
|
||||
Ondřej Surý - running coverity analysis tool on 0.9 dev version.
|
||||
Alexander Gall - multihomed, anycast testing of unbound resolver server.
|
||||
Zdenek Vasicek and Marek Vavrusa - python module.
|
||||
cz.nic - sponsoring 'summer of code' development by Zdenek and Marek.
|
||||
Brett Carr - windows beta testing.
|
||||
Luca Bruno - patch for windows support in libunbound hosts and resolvconf().
|
||||
Tom Hendrikx - contributed split-itar.sh a useful script to 5011-track ITAR.
|
||||
Daisuke HIGASHI - patch for rrset-roundrobin and minimal-responses.
|
4780
contrib/unbound/doc/Changelog
Normal file
4780
contrib/unbound/doc/Changelog
Normal file
File diff suppressed because it is too large
Load Diff
100
contrib/unbound/doc/FEATURES
Normal file
100
contrib/unbound/doc/FEATURES
Normal file
@ -0,0 +1,100 @@
|
||||
Unbound Features
|
||||
|
||||
(C) Copyright 2008, Wouter Wijngaards, NLnet Labs.
|
||||
|
||||
|
||||
This document describes the features and RFCs that unbound
|
||||
adheres to, and which ones are decided to be out of scope.
|
||||
|
||||
|
||||
Big Features
|
||||
------------
|
||||
Recursive service.
|
||||
Caching service.
|
||||
Forwarding and stub zones.
|
||||
Very limited authoritative service.
|
||||
DNSSEC Validation options.
|
||||
EDNS0, NSEC3, IPv6, DNAME, Unknown-RR-types.
|
||||
RSASHA256, GOST, ECDSA, SHA384 DNSSEC algorithms.
|
||||
|
||||
Details
|
||||
-------
|
||||
Processing support
|
||||
RFC 1034-1035: as a recursive, caching server. Not authoritative.
|
||||
including CNAMEs, referrals, wildcards, classes, ...
|
||||
AAAA type, and IP6 dual stack support.
|
||||
type ANY queries are supported, class ANY queries are supported.
|
||||
RFC 4033-4035: as a validating caching server (unbound daemon).
|
||||
as a validating stub (libunbound).
|
||||
RFC 1918.
|
||||
RFC 1995, 1996, 2136: not authoritative, so no AXFR, IXFR, NOTIFY or
|
||||
dynamic update services are appropriate.
|
||||
RFC 2181: completely, including the trust model, keeping rrsets together.
|
||||
RFC 2308: TTL directive, and the rest of the RFC too.
|
||||
RFC 2671: EDNS0 support, default advertisement 4Kb size.
|
||||
RFC 2672: DNAME support.
|
||||
RFC 3597: Unknown RR type support.
|
||||
RFC 4343: case insensitive handling of domain names.
|
||||
RFC 4509: SHA256 DS hash.
|
||||
RFC 4592: wildcards.
|
||||
RFC 4697: No DNS Resolution Misbehavior.
|
||||
RFC 5011: update of trust anchors with timers.
|
||||
RFC 5155: NSEC3, NSEC3PARAM types
|
||||
RFC 5358: reflectors-are-evil: access control list for recursive
|
||||
service. In fact for all DNS service so cache snooping is halted.
|
||||
RFC 5452: forgery resilience. all recommendations followed.
|
||||
RFC 5702: RSASHA256 signature algorithm.
|
||||
RFC 5933: GOST signature algorithm.
|
||||
RFC 6303: default local zones.
|
||||
It is possible to block zones or return an address for localhost.
|
||||
This is a very limited authoritative service. Defaults as in draft.
|
||||
RFC 6604: xNAME RCODE and status bits.
|
||||
RFC 6605: ECDSA signature algorithm, SHA384 DS hash.
|
||||
|
||||
chroot and drop-root-privileges support, default enabled in config file.
|
||||
|
||||
AD bit in query can be used to request AD bit in response (w/o using DO bit).
|
||||
CD bit in query can be used to request bogus data.
|
||||
UDP and TCP service is provided downstream.
|
||||
UDP and TCP are used to request from upstream servers.
|
||||
SSL wrapped TCP service can be used upstream and provided downstream.
|
||||
Multiple queries can be made over a TCP stream.
|
||||
|
||||
No TSIG support at this time.
|
||||
No SIG0 support at this time.
|
||||
No dTLS support at this time.
|
||||
This is not a DNS statistics package, but some operationally useful
|
||||
values are provided via unbound-control stats.
|
||||
TXT RRs from the Chaos class (id.server, hostname.bind, ...) are supported.
|
||||
|
||||
draft-0x20: implemented, use caps-for-id option to enable use.
|
||||
Also implements bitwise echo of the query to support downstream 0x20.
|
||||
draft-ietf-dnsop-resolver-priming(-00): can prime and can fallback to
|
||||
a safety belt list.
|
||||
draft-ietf-dnsop-dnssec-trust-anchor(-01): DS records can be configured
|
||||
as trust anchors. Also DNSKEYs are allowed, by the way.
|
||||
draft-ietf-dnsext-dnssec-bis-updates: supported.
|
||||
|
||||
Record type syntax support, extensive, from lib ldns.
|
||||
For these types only syntax and parsing support is needed.
|
||||
RFC 1034-1035: basic RR types.
|
||||
RFC 1183: RP, AFSDB, X25, ISDN, RT
|
||||
RFC 1706: NSAP
|
||||
RFC 2535: KEY, SIG, NXT: treated as unknown data, syntax is parsed (obsolete).
|
||||
2163: PX
|
||||
AAAA type
|
||||
1876: LOC type
|
||||
2782: SRV type
|
||||
2915: NAPTR type.
|
||||
2230: KX type.
|
||||
2538: CERT type.
|
||||
2672: DNAME type.
|
||||
OPT type
|
||||
3123: APL
|
||||
SSHFP type
|
||||
4025: IPSECKEY
|
||||
4033-4035: DS, RRSIG, NSEC, DNSKEY
|
||||
4701: DHCID
|
||||
5155: NSEC3, NSEC3PARAM
|
||||
4408: SPF
|
||||
|
30
contrib/unbound/doc/LICENSE
Normal file
30
contrib/unbound/doc/LICENSE
Normal file
@ -0,0 +1,30 @@
|
||||
Copyright (c) 2007, 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.
|
150
contrib/unbound/doc/README
Normal file
150
contrib/unbound/doc/README
Normal file
@ -0,0 +1,150 @@
|
||||
README for Unbound 1.4.17
|
||||
Copyright 2007 NLnet Labs
|
||||
http://unbound.net
|
||||
|
||||
This software is under BSD license, see LICENSE for details.
|
||||
|
||||
* Download the latest release version of this software from
|
||||
http://unbound.net
|
||||
or get a beta version from the svn repository at
|
||||
http://unbound.net/svn/
|
||||
|
||||
* Uses the following libraries;
|
||||
* ldns http://www.nlnetlabs.nl/ldns/ (BSD license)
|
||||
(required) can use ldns build directory directly with --with-ldns=path.
|
||||
* libevent http://www.monkey.org/~provos/libevent/ (BSD license)
|
||||
(optional) can use builtin alternative instead.
|
||||
|
||||
* Make and install: ./configure; make; make install
|
||||
* --with-ldns=/path/to/ldns
|
||||
It will dynamically link against it.
|
||||
* --with-libevent=/path/to/libevent
|
||||
Can be set to either the system install or the build directory.
|
||||
--with-libevent=no (default) gives a builtin alternative
|
||||
implementation. libevent is useful when having many (thousands)
|
||||
of outgoing ports. This improves randomization and spoof
|
||||
resistance. For the default of 16 ports the builtin alternative
|
||||
works well and is a little faster.
|
||||
* --with-libexpat=/path/to/libexpat
|
||||
Can be set to the install directory of libexpat.
|
||||
* --without-pthreads
|
||||
This disables pthreads. Without this option the pthreads library
|
||||
is detected automatically. Use this option to disable threading
|
||||
altogether, or, on Solaris, also use --with(out)-solaris-threads.
|
||||
* --enable-checking
|
||||
This enables assertions in the code that guard against a variety of
|
||||
programming errors, among which buffer overflows. The program exits
|
||||
with an error if an assertion fails (but the buffer did not overflow).
|
||||
* --enable-static-exe
|
||||
This enables a debug option to statically link, against ldns and
|
||||
libevent libraries.
|
||||
* --enable-lock-checks
|
||||
This enables a debug option to check lock and unlock calls. It needs
|
||||
a recent pthreads library to work.
|
||||
* --enable-alloc-checks
|
||||
This enables a debug option to check malloc (calloc, realloc, free).
|
||||
The server periodically checks if the amount of memory used fits with
|
||||
the amount of memory it thinks it should be using, and reports
|
||||
memory usage in detail.
|
||||
* --with-conf-file=filename
|
||||
Set default location of config file,
|
||||
the default is /usr/local/etc/unbound/unbound.conf.
|
||||
* --with-pidfile=filename
|
||||
Set default location of pidfile,
|
||||
the default is /usr/local/etc/unbound/unbound.pid.
|
||||
* --with-run-dir=path
|
||||
Set default working directory,
|
||||
the default is /usr/local/etc/unbound.
|
||||
* --with-chroot-dir=path
|
||||
Set default chroot directory,
|
||||
the default is /usr/local/etc/unbound.
|
||||
* --with-rootkey-file=path
|
||||
Set the default root.key path. This file is read and written.
|
||||
the default is /usr/local/etc/unbound/root.key
|
||||
* --with-rootcert-file=path
|
||||
Set the default root update certificate path. A builtin certificate
|
||||
is used if this file is empty or does not exist.
|
||||
the default is /usr/local/etc/unbound/icannbundle.pem
|
||||
* --with-username=user
|
||||
Set default user name to change to,
|
||||
the default is the "unbound" user.
|
||||
* --with-pyunbound
|
||||
Create libunbound wrapper usable from python.
|
||||
Needs python-devel and swig development tools.
|
||||
* --with-pythonmodule
|
||||
Compile the python module that processes responses in the server.
|
||||
* --disable-sha2
|
||||
Disable support for RSASHA256 and RSASHA512 crypto.
|
||||
* --disable-gost
|
||||
Disable support for GOST crypto, RFC 5933.
|
||||
|
||||
* 'make test' runs a series of self checks.
|
||||
|
||||
Known issues
|
||||
------------
|
||||
o If there are no replies for a forward or stub zone, for a reverse zone,
|
||||
you may need to add a local-zone: name transparent or nodefault to the
|
||||
server: section of the config file to unblock the reverse zone.
|
||||
Only happens for (sub)zones that are blocked by default; e.g. 10.in-addr.arpa
|
||||
o If libevent is older (before 1.3c), unbound will exit instead of reload
|
||||
on sighup. On a restart 'did not exit gracefully last time' warning is
|
||||
printed. Perform ./configure --with-libevent=no or update libevent, rerun
|
||||
configure and recompile unbound to make sighup work correctly.
|
||||
It is strongly suggested to use a recent version of libevent.
|
||||
o If you are not receiving the correct source IP address on replies (e.g.
|
||||
you are running a multihomed, anycast server), the interface-automatic
|
||||
option can be enabled to set socket options to achieve the correct
|
||||
source IP address on UDP replies. Listing all IP addresses explicitly in
|
||||
the config file is an alternative. The interface-automatic option uses
|
||||
non portable socket options, Linux and FreeBSD should work fine.
|
||||
o The warning 'openssl has no entropy, seeding with time', with chroot
|
||||
enabled, may be solved with a symbolic link to /dev/random from <chrootdir>.
|
||||
o On Solaris 5.10 some libtool packages from repositories do not work with
|
||||
gcc, showing errors gcc: unrecognized option `-KPIC'
|
||||
To solve this do ./configure libtool=./libtool [your options...].
|
||||
On Solaris you may pass CFLAGS="-xO4 -xtarget=generic" if you use sun-cc.
|
||||
o If unbound-control (or munin graphs) do not work, this can often be because
|
||||
the unbound-control-setup script creates the keys with restricted
|
||||
permissions, and the files need to be made readable or ownered by both the
|
||||
unbound daemon and unbound-control.
|
||||
o Crosscompile seems to hang. You tried to install unbound under wine.
|
||||
wine regedit and remove all the unbound entries from the registry or
|
||||
delete .wine/drive_c.
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
o Unbound was written in portable C by Wouter Wijngaards (NLnet Labs).
|
||||
o Thanks to David Blacka and Matt Larson (Verisign) for the unbound-java
|
||||
prototype. Design and code from that prototype has been used to create
|
||||
this program. Such as the iterator state machine and the cache design.
|
||||
o Other code origins are from the NSD (NLnet Labs) and LDNS (NLnet Labs)
|
||||
projects. Such as buffer, region-allocator and red-black tree code.
|
||||
o See Credits file for contributors.
|
||||
|
||||
|
||||
Your Support
|
||||
------------
|
||||
NLnet Labs offers all of its software products as open source, most are
|
||||
published under a BSD license. You can download them, not only from the
|
||||
NLnet Labs website but also through the various OS distributions for
|
||||
which NSD, ldns, and Unbound are packaged. We therefore have little idea
|
||||
who uses our software in production environments and have no direct ties
|
||||
with 'our customers'.
|
||||
|
||||
Therefore, we ask you to contact us at users@NLnetLabs.nl and tell us
|
||||
whether you use one of our products in your production environment,
|
||||
what that environment looks like, and maybe even share some praise.
|
||||
We would like to refer to the fact that your organization is using our
|
||||
products. We will only do that if you explicitly allow us. In all other
|
||||
cases we will keep the information you share with us to ourselves.
|
||||
|
||||
In addition to the moral support you can also support us
|
||||
financially. NLnet Labs is a recognized not-for-profit charity foundation
|
||||
that is chartered to develop open-source software and open-standards
|
||||
for the Internet. If you use our software to satisfaction please express
|
||||
that by giving us a donation. For small donations PayPal can be used. For
|
||||
larger and regular donations please contact us at users@NLnetLabs.nl. Also
|
||||
see http://www.nlnetlabs.nl/labs/contributors/.
|
||||
|
||||
|
||||
* mailto:unbound-bugs@nlnetlabs.nl
|
17
contrib/unbound/doc/README.svn
Normal file
17
contrib/unbound/doc/README.svn
Normal file
@ -0,0 +1,17 @@
|
||||
README.svn
|
||||
|
||||
For a svn checkout
|
||||
* configure script, aclocal.m4, as well as yacc/lex output files are
|
||||
committed to the repository.
|
||||
* use --enable-debug flag for configure to enable dependency tracking and
|
||||
assertions, otherwise, use make clean; make after svn update.
|
||||
|
||||
* Note changes in the Changelog.
|
||||
* Every check-in a postcommit hook is run
|
||||
(the postcommit hook is in the svn/unbound/hooks directory).
|
||||
* generates commit email with your changes and comment.
|
||||
* compiles and runs the tests (with testcode/do-tests.sh).
|
||||
* If build errors or test errors happen
|
||||
* Please fix your errors and commit again.
|
||||
|
||||
* Use gnu make to compile, make or 'gmake'.
|
24
contrib/unbound/doc/README.tests
Normal file
24
contrib/unbound/doc/README.tests
Normal file
@ -0,0 +1,24 @@
|
||||
README unbound tests
|
||||
|
||||
For a quick test that runs unit tests and state machine tests, use
|
||||
make test
|
||||
|
||||
There is a long test setup for unbound that needs tools installed. Use
|
||||
make longtest
|
||||
To make and run the long tests. The results are summarized at the end.
|
||||
|
||||
You need to have the following programs installed and in your PATH.
|
||||
* dig - from the bind-tools package. Used to send DNS queries.
|
||||
* splint (optional) - for lint test
|
||||
* doxygen (optional) - for doc completeness test
|
||||
* ldns-testns - from ldns examples. Used as DNS auth server.
|
||||
* xxd and nc (optional) - for (malformed) packet transmission.
|
||||
The optional programs are detected and can be omitted.
|
||||
|
||||
testdata/ contains the data for tests.
|
||||
testcode/ contains scripts and c code for the tests.
|
||||
|
||||
do-tests.sh : runs all the tests in the testdata directory.
|
||||
testbed.sh : compiles on a set of (user specific) hosts and runs do-tests.
|
||||
|
||||
Tests are run using testcode/mini_tpkg.sh.
|
76
contrib/unbound/doc/TODO
Normal file
76
contrib/unbound/doc/TODO
Normal file
@ -0,0 +1,76 @@
|
||||
TODO items. These are interesting todo items.
|
||||
o understand synthesized DNAMEs, so those TTL=0 packets are cached properly.
|
||||
o NSEC/NSEC3 aggressive negative caching, so that updates to NSEC/NSEC3
|
||||
will result in proper negative responses.
|
||||
o (option) where port 53 is used for send and receive, no other ports are used.
|
||||
o (option) to not send replies to clients after a timeout of (say 5 secs) has
|
||||
passed, but keep task active for later retries by client.
|
||||
o (option) private TTL feature (always report TTL x in answers).
|
||||
o (option) pretend-dnssec-unaware, and pretend-edns-unaware modes for workshops.
|
||||
o delegpt use rbtree for ns-list, to avoid slowdown for very large NS sets.
|
||||
o (option) reprime and refresh oft used data before timeout.
|
||||
o (option) retain prime results in a overlaid roothints file.
|
||||
o (option) store primed key data in a overlaid keyhints file (sort of like drafttimers).
|
||||
o windows version, auto update feature, a query to check for the version.
|
||||
o command the server with TSIG inband. get-config, clearcache,
|
||||
get stats, get memstats, get ..., reload, clear one zone from cache
|
||||
o NSID rfc 5001 support.
|
||||
o timers rfc 5011 support.
|
||||
o Treat YXDOMAIN from a DNAME properly, in iterator (not throwaway), validator.
|
||||
o make timeout backoffs randomized (a couple percent random) to spread traffic.
|
||||
o inspect date on executable, then warn user in log if its more than 1 year.
|
||||
o (option) proactively prime root, stubs and trust anchors, feature.
|
||||
early failure, faster on first query, but more traffic.
|
||||
o library add convenience functions for A, AAAA, PTR, getaddrinfo, libresolve.
|
||||
o library add function to validate input from app that is signed.
|
||||
o add dynamic-update requests (making a dynupd request) to libunbound api.
|
||||
o SIG(0) and TSIG.
|
||||
o support OPT record placement on recv anywhere in the additional section.
|
||||
o add local-file: config with authority features.
|
||||
o (option) to make local-data answers be secure for libunbound (default=no)
|
||||
o (option) to make chroot: copy all needed files into jail (or make jail)
|
||||
perhaps also print reminder to link /dev/random and sysloghack.
|
||||
o overhaul outside-network servicedquery to merge with udpwait and tcpwait,
|
||||
to make timers in servicedquery independent of udpwait queues.
|
||||
o check into rebinding ports for efficiency, configure time test.
|
||||
o EVP hardware crypto support.
|
||||
o option to ignore all inception and expiration dates for rrsigs.
|
||||
o cleaner code; return and func statements on newline.
|
||||
o memcached module that sits before validator module; checks for memcached
|
||||
data (on local lan), stores recursion lookup. Provides one cache for multiple resolver machines, coherent reply content in anycast setup.
|
||||
o no openssl_add_all_algorithms, but only the ones necessary, less space.
|
||||
o listen to NOTIFY messages for zones and flush the cache for that zone
|
||||
if received. Useful when also having a stub to that auth server.
|
||||
Needs proper protection, TSIG, in place.
|
||||
o winevent - do not go more than 64 fds (by polling with select one by
|
||||
one), win95/98 have 100fd limit in the kernel, so this ruins w9x portability.
|
||||
|
||||
*** Features features, for later
|
||||
* dTLS, TLS, look to need special port numbers, cert storage, recent libssl.
|
||||
* aggressive negative caching for NSEC, NSEC3.
|
||||
* multiple queries per question, server exploration, server selection.
|
||||
* support TSIG on queries, for validating resolver deployment.
|
||||
* retry-mode, where a bogus result triggers a retry-mode query, where a list
|
||||
of responses over a time interval is collected, and each is validated.
|
||||
or try in TCP mode. Do not 'try all servers several times', since we must
|
||||
not create packet storms with operator errors.
|
||||
o on windows version, implement that OS ancillary data capabilities for
|
||||
interface-automatic. IPPKTINFO, IP6PKTINFO for WSARecvMsg, WSASendMsg.
|
||||
o local-zone directive with authority service, full authority server
|
||||
is a non-goal.
|
||||
o infra and lame cache: easier size config (in Mb), show usage in graphs.
|
||||
- store time of dump in cachedumps, so that on a load the ttls can be
|
||||
compared to the absolute time, and now-expired items can be dealt with.
|
||||
|
||||
later
|
||||
- selective verbosity; ubcontrol trace example.com
|
||||
- cache fork-dump, pre-load
|
||||
- for fwds, send queries to N servers in fwd-list, use first reply.
|
||||
document high scalable, high available unbound setup onepager.
|
||||
- prefetch DNSKEY when DS in delegation seen (nonCD, underTA).
|
||||
- use libevent if available on system by default(?), default outgoing 256to1024
|
||||
|
||||
[1] BIND-like query logging to see who's looking up what and when
|
||||
[2] more logging about stuff like SERVFAIL and REFUSED responses
|
||||
[3] a Makefile that works without gnumake
|
||||
|
70
contrib/unbound/doc/control_proto_spec.txt
Normal file
70
contrib/unbound/doc/control_proto_spec.txt
Normal file
@ -0,0 +1,70 @@
|
||||
|
||||
Specification for the unbound-control protocol.
|
||||
|
||||
Server listens on 8953 TCP (localhost by default). Client connects,
|
||||
SSLv3 or TLSv1 connection setup (server selfsigned certificate,
|
||||
client has cert signed by server certificate).
|
||||
|
||||
Port 8953 is registered with IANA as:
|
||||
ub-dns-control 8953/tcp unbound dns nameserver control
|
||||
# Wouter Wijngaards <wouter&nlnetlabs.nl> 10 May 2011
|
||||
On may 11 2011, ticket [IANA #442315].
|
||||
|
||||
Query and Response
|
||||
------------------
|
||||
Client sends
|
||||
UBCT[version] [commandline] \n
|
||||
fixed string UBCT1 (for version 1), then an ascii text line,
|
||||
with a command, some whitespace allowed. Line ends with '\n'.
|
||||
|
||||
Server executes command. And sends reply in ascii text over channel,
|
||||
closes the channel when done.
|
||||
in case of error the first line of the response is:
|
||||
error <descriptive text possible> \n
|
||||
or the remainder is data of the response, for many commands the
|
||||
response is 'ok\n'.
|
||||
|
||||
Queries and responses
|
||||
---------------------
|
||||
stop
|
||||
stops the server.
|
||||
reload
|
||||
reloads the config file, and flushes the cache.
|
||||
verbosity <new value>
|
||||
Change logging verbosity to new value.
|
||||
stats
|
||||
output is a list of [name]=[value] lines.
|
||||
clears the counters.
|
||||
dump_cache
|
||||
output is a text representation of the cache contents.
|
||||
data ends with a line 'EOF' before connection close.
|
||||
load_cache
|
||||
client sends cache contents (like from dump_cache), which is stored
|
||||
in the cache. end of data indicated with a line with 'EOF' on it.
|
||||
The data is sent after the query line.
|
||||
flush <name>
|
||||
flushes some information regarding the name from the cache.
|
||||
removes the A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV, NAPTR types.
|
||||
Does not remove other types.
|
||||
flush_type <name> <RR type>
|
||||
removes rrtype entry from the cache.
|
||||
flush_zone <name>
|
||||
removes name and everything below that name from the cache.
|
||||
has to search through the cache item by item, so this is slow.
|
||||
lookup <name>
|
||||
see what servers would be queried for a lookup of the given name.
|
||||
local_zone_remove <name of local-zone entry>
|
||||
the local-zone entry is removed.
|
||||
All data from the local zone is also deleted.
|
||||
If it did not exist, nothing happens.
|
||||
local_zone <name of local zone> <type>
|
||||
As the config file entry. Adds new local zone or updates
|
||||
existing zone type.
|
||||
local_data_remove <name>
|
||||
Removes local-data (all types) name.
|
||||
local_data <resource record string>
|
||||
Add new local data record (on the rest of the line).
|
||||
local_data_add www.example.com. IN A 192.0.2.2
|
||||
if no local_zone exists for it; a transparent zone with the same
|
||||
name as the data is created.
|
||||
Other commands in the unbound-control manual page.
|
536
contrib/unbound/doc/example.conf.in
Normal file
536
contrib/unbound/doc/example.conf.in
Normal file
@ -0,0 +1,536 @@
|
||||
#
|
||||
# Example configuration file.
|
||||
#
|
||||
# See unbound.conf(5) man page, version 1.4.17.
|
||||
#
|
||||
# this is a comment.
|
||||
|
||||
#Use this to include other text into the file.
|
||||
#include: "otherfile.conf"
|
||||
|
||||
# The server clause sets the main parameters.
|
||||
server:
|
||||
# whitespace is not necessary, but looks cleaner.
|
||||
|
||||
# verbosity number, 0 is least verbose. 1 is default.
|
||||
verbosity: 1
|
||||
|
||||
# print statistics to the log (for every thread) every N seconds.
|
||||
# Set to "" or 0 to disable. Default is disabled.
|
||||
# statistics-interval: 0
|
||||
|
||||
# enable cumulative statistics, without clearing them after printing.
|
||||
# statistics-cumulative: no
|
||||
|
||||
# enable extended statistics (query types, answer codes, status)
|
||||
# printed from unbound-control. default off, because of speed.
|
||||
# extended-statistics: no
|
||||
|
||||
# number of threads to create. 1 disables threading.
|
||||
# num-threads: 1
|
||||
|
||||
# specify the interfaces to answer queries from by ip-address.
|
||||
# The default is to listen to localhost (127.0.0.1 and ::1).
|
||||
# specify 0.0.0.0 and ::0 to bind to all available interfaces.
|
||||
# specify every interface[@port] on a new 'interface:' labelled line.
|
||||
# The listen interfaces are not changed on reload, only on restart.
|
||||
# interface: 192.0.2.153
|
||||
# interface: 192.0.2.154
|
||||
# interface: 192.0.2.154@5003
|
||||
# interface: 2001:DB8::5
|
||||
|
||||
# enable this feature to copy the source address of queries to reply.
|
||||
# Socket options are not supported on all platforms. experimental.
|
||||
# interface-automatic: no
|
||||
|
||||
# port to answer queries from
|
||||
# port: 53
|
||||
|
||||
# specify the interfaces to send outgoing queries to authoritative
|
||||
# server from by ip-address. If none, the default (all) interface
|
||||
# is used. Specify every interface on a 'outgoing-interface:' line.
|
||||
# outgoing-interface: 192.0.2.153
|
||||
# outgoing-interface: 2001:DB8::5
|
||||
# outgoing-interface: 2001:DB8::6
|
||||
|
||||
# number of ports to allocate per thread, determines the size of the
|
||||
# port range that can be open simultaneously. About double the
|
||||
# num-queries-per-thread, or, use as many as the OS will allow you.
|
||||
# outgoing-range: 4096
|
||||
|
||||
# permit unbound to use this port number or port range for
|
||||
# making outgoing queries, using an outgoing interface.
|
||||
# outgoing-port-permit: 32768
|
||||
|
||||
# deny unbound the use this of port number or port range for
|
||||
# making outgoing queries, using an outgoing interface.
|
||||
# Use this to make sure unbound does not grab a UDP port that some
|
||||
# other server on this computer needs. The default is to avoid
|
||||
# IANA-assigned port numbers.
|
||||
# outgoing-port-avoid: "3200-3208"
|
||||
|
||||
# number of outgoing simultaneous tcp buffers to hold per thread.
|
||||
# outgoing-num-tcp: 10
|
||||
|
||||
# number of incoming simultaneous tcp buffers to hold per thread.
|
||||
# incoming-num-tcp: 10
|
||||
|
||||
# buffer size for UDP port 53 incoming (SO_RCVBUF socket option).
|
||||
# 0 is system default. Use 4m to catch query spikes for busy servers.
|
||||
# so-rcvbuf: 0
|
||||
|
||||
# buffer size for UDP port 53 outgoing (SO_SNDBUF socket option).
|
||||
# 0 is system default. Use 4m to handle spikes on very busy servers.
|
||||
# so-sndbuf: 0
|
||||
|
||||
# EDNS reassembly buffer to advertise to UDP peers (the actual buffer
|
||||
# is set with msg-buffer-size). 1480 can solve fragmentation (timeouts).
|
||||
# edns-buffer-size: 4096
|
||||
|
||||
# buffer size for handling DNS data. No messages larger than this
|
||||
# size can be sent or received, by UDP or TCP. In bytes.
|
||||
# msg-buffer-size: 65552
|
||||
|
||||
# the amount of memory to use for the message cache.
|
||||
# plain value in bytes or you can append k, m or G. default is "4Mb".
|
||||
# msg-cache-size: 4m
|
||||
|
||||
# the number of slabs to use for the message cache.
|
||||
# the number of slabs must be a power of 2.
|
||||
# more slabs reduce lock contention, but fragment memory usage.
|
||||
# msg-cache-slabs: 4
|
||||
|
||||
# the number of queries that a thread gets to service.
|
||||
# num-queries-per-thread: 1024
|
||||
|
||||
# if very busy, 50% queries run to completion, 50% get timeout in msec
|
||||
# jostle-timeout: 200
|
||||
|
||||
# the amount of memory to use for the RRset cache.
|
||||
# plain value in bytes or you can append k, m or G. default is "4Mb".
|
||||
# rrset-cache-size: 4m
|
||||
|
||||
# the number of slabs to use for the RRset cache.
|
||||
# the number of slabs must be a power of 2.
|
||||
# more slabs reduce lock contention, but fragment memory usage.
|
||||
# rrset-cache-slabs: 4
|
||||
|
||||
# the time to live (TTL) value lower bound, in seconds. Default 0.
|
||||
# If more than an hour could easily give trouble due to stale data.
|
||||
# cache-min-ttl: 0
|
||||
|
||||
# the time to live (TTL) value cap for RRsets and messages in the
|
||||
# cache. Items are not cached for longer. In seconds.
|
||||
# cache-max-ttl: 86400
|
||||
|
||||
# the time to live (TTL) value for cached roundtrip times, lameness and
|
||||
# EDNS version information for hosts. In seconds.
|
||||
# infra-host-ttl: 900
|
||||
|
||||
# the number of slabs to use for the Infrastructure cache.
|
||||
# the number of slabs must be a power of 2.
|
||||
# more slabs reduce lock contention, but fragment memory usage.
|
||||
# infra-cache-slabs: 4
|
||||
|
||||
# the maximum number of hosts that are cached (roundtrip, EDNS, lame).
|
||||
# infra-cache-numhosts: 10000
|
||||
|
||||
# Enable IPv4, "yes" or "no".
|
||||
# do-ip4: yes
|
||||
|
||||
# Enable IPv6, "yes" or "no".
|
||||
# do-ip6: yes
|
||||
|
||||
# Enable UDP, "yes" or "no".
|
||||
# do-udp: yes
|
||||
|
||||
# Enable TCP, "yes" or "no".
|
||||
# do-tcp: yes
|
||||
|
||||
# upstream connections use TCP only (and no UDP), "yes" or "no"
|
||||
# useful for tunneling scenarios, default no.
|
||||
# tcp-upstream: no
|
||||
|
||||
# Detach from the terminal, run in background, "yes" or "no".
|
||||
# do-daemonize: yes
|
||||
|
||||
# control which clients are allowed to make (recursive) queries
|
||||
# to this server. Specify classless netblocks with /size and action.
|
||||
# By default everything is refused, except for localhost.
|
||||
# Choose deny (drop message), refuse (polite error reply),
|
||||
# allow (recursive ok), allow_snoop (recursive and nonrecursive ok)
|
||||
# access-control: 0.0.0.0/0 refuse
|
||||
# access-control: 127.0.0.0/8 allow
|
||||
# access-control: ::0/0 refuse
|
||||
# access-control: ::1 allow
|
||||
# access-control: ::ffff:127.0.0.1 allow
|
||||
|
||||
# if given, a chroot(2) is done to the given directory.
|
||||
# i.e. you can chroot to the working directory, for example,
|
||||
# for extra security, but make sure all files are in that directory.
|
||||
#
|
||||
# If chroot is enabled, you should pass the configfile (from the
|
||||
# commandline) as a full path from the original root. After the
|
||||
# chroot has been performed the now defunct portion of the config
|
||||
# file path is removed to be able to reread the config after a reload.
|
||||
#
|
||||
# All other file paths (working dir, logfile, roothints, and
|
||||
# key files) can be specified in several ways:
|
||||
# o as an absolute path relative to the new root.
|
||||
# o as a relative path to the working directory.
|
||||
# o as an absolute path relative to the original root.
|
||||
# In the last case the path is adjusted to remove the unused portion.
|
||||
#
|
||||
# The pid file can be absolute and outside of the chroot, it is
|
||||
# written just prior to performing the chroot and dropping permissions.
|
||||
#
|
||||
# Additionally, unbound may need to access /dev/random (for entropy).
|
||||
# How to do this is specific to your OS.
|
||||
#
|
||||
# If you give "" no chroot is performed. The path must not end in a /.
|
||||
# chroot: "@UNBOUND_CHROOT_DIR@"
|
||||
|
||||
# if given, user privileges are dropped (after binding port),
|
||||
# and the given username is assumed. Default is user "unbound".
|
||||
# If you give "" no privileges are dropped.
|
||||
# username: "@UNBOUND_USERNAME@"
|
||||
|
||||
# the working directory. The relative files in this config are
|
||||
# relative to this directory. If you give "" the working directory
|
||||
# is not changed.
|
||||
# directory: "@UNBOUND_RUN_DIR@"
|
||||
|
||||
# the log file, "" means log to stderr.
|
||||
# Use of this option sets use-syslog to "no".
|
||||
# logfile: ""
|
||||
|
||||
# Log to syslog(3) if yes. The log facility LOG_DAEMON is used to
|
||||
# log to, with identity "unbound". If yes, it overrides the logfile.
|
||||
# use-syslog: yes
|
||||
|
||||
# print UTC timestamp in ascii to logfile, default is epoch in seconds.
|
||||
# log-time-ascii: no
|
||||
|
||||
# print one line with time, IP, name, type, class for every query.
|
||||
# log-queries: no
|
||||
|
||||
# the pid file. Can be an absolute path outside of chroot/work dir.
|
||||
# pidfile: "@UNBOUND_PIDFILE@"
|
||||
|
||||
# file to read root hints from.
|
||||
# get one from ftp://FTP.INTERNIC.NET/domain/named.cache
|
||||
# root-hints: ""
|
||||
|
||||
# enable to not answer id.server and hostname.bind queries.
|
||||
# hide-identity: no
|
||||
|
||||
# enable to not answer version.server and version.bind queries.
|
||||
# hide-version: no
|
||||
|
||||
# the identity to report. Leave "" or default to return hostname.
|
||||
# identity: ""
|
||||
|
||||
# the version to report. Leave "" or default to return package version.
|
||||
# version: ""
|
||||
|
||||
# the target fetch policy.
|
||||
# series of integers describing the policy per dependency depth.
|
||||
# The number of values in the list determines the maximum dependency
|
||||
# depth the recursor will pursue before giving up. Each integer means:
|
||||
# -1 : fetch all targets opportunistically,
|
||||
# 0: fetch on demand,
|
||||
# positive value: fetch that many targets opportunistically.
|
||||
# Enclose the list of numbers between quotes ("").
|
||||
# target-fetch-policy: "3 2 1 0 0"
|
||||
|
||||
# Harden against very small EDNS buffer sizes.
|
||||
# harden-short-bufsize: no
|
||||
|
||||
# Harden against unseemly large queries.
|
||||
# harden-large-queries: no
|
||||
|
||||
# Harden against out of zone rrsets, to avoid spoofing attempts.
|
||||
# harden-glue: yes
|
||||
|
||||
# Harden against receiving dnssec-stripped data. If you turn it
|
||||
# off, failing to validate dnskey data for a trustanchor will
|
||||
# trigger insecure mode for that zone (like without a trustanchor).
|
||||
# Default on, which insists on dnssec data for trust-anchored zones.
|
||||
# harden-dnssec-stripped: yes
|
||||
|
||||
# Harden against queries that fall under dnssec-signed nxdomain names.
|
||||
# harden-below-nxdomain: no
|
||||
|
||||
# Harden the referral path by performing additional queries for
|
||||
# infrastructure data. Validates the replies (if possible).
|
||||
# Default off, because the lookups burden the server. Experimental
|
||||
# implementation of draft-wijngaards-dnsext-resolver-side-mitigation.
|
||||
# harden-referral-path: no
|
||||
|
||||
# Use 0x20-encoded random bits in the query to foil spoof attempts.
|
||||
# This feature is an experimental implementation of draft dns-0x20.
|
||||
# use-caps-for-id: no
|
||||
|
||||
# Enforce privacy of these addresses. Strips them away from answers.
|
||||
# It may cause DNSSEC validation to additionally mark it as bogus.
|
||||
# Protects against 'DNS Rebinding' (uses browser as network proxy).
|
||||
# Only 'private-domain' and 'local-data' names are allowed to have
|
||||
# these private addresses. No default.
|
||||
# private-address: 10.0.0.0/8
|
||||
# private-address: 172.16.0.0/12
|
||||
# private-address: 192.168.0.0/16
|
||||
# private-address: 169.254.0.0/16
|
||||
# private-address: fd00::/8
|
||||
# private-address: fe80::/10
|
||||
|
||||
# Allow the domain (and its subdomains) to contain private addresses.
|
||||
# local-data statements are allowed to contain private addresses too.
|
||||
# private-domain: "example.com"
|
||||
|
||||
# If nonzero, unwanted replies are not only reported in statistics,
|
||||
# but also a running total is kept per thread. If it reaches the
|
||||
# threshold, a warning is printed and a defensive action is taken,
|
||||
# the cache is cleared to flush potential poison out of it.
|
||||
# A suggested value is 10000000, the default is 0 (turned off).
|
||||
# unwanted-reply-threshold: 0
|
||||
|
||||
# Do not query the following addresses. No DNS queries are sent there.
|
||||
# List one address per entry. List classless netblocks with /size,
|
||||
# do-not-query-address: 127.0.0.1/8
|
||||
# do-not-query-address: ::1
|
||||
|
||||
# if yes, the above default do-not-query-address entries are present.
|
||||
# if no, localhost can be queried (for testing and debugging).
|
||||
# do-not-query-localhost: yes
|
||||
|
||||
# if yes, perform prefetching of almost expired message cache entries.
|
||||
# prefetch: no
|
||||
|
||||
# if yes, perform key lookups adjacent to normal lookups.
|
||||
# prefetch-key: no
|
||||
|
||||
# if yes, Unbound rotates RRSet order in response.
|
||||
# rrset-roundrobin: no
|
||||
|
||||
# if yes, Unbound doesn't insert authority/additional sections
|
||||
# into response messages when those sections are not required.
|
||||
# minimal-responses: no
|
||||
|
||||
# module configuration of the server. A string with identifiers
|
||||
# separated by spaces. "iterator" or "validator iterator"
|
||||
# module-config: "validator iterator"
|
||||
|
||||
# File with trusted keys, kept uptodate using RFC5011 probes,
|
||||
# initial file like trust-anchor-file, then it stores metadata.
|
||||
# Use several entries, one per domain name, to track multiple zones.
|
||||
#
|
||||
# If you want to perform DNSSEC validation, run unbound-anchor before
|
||||
# you start unbound (i.e. in the system boot scripts). And enable:
|
||||
# Please note usage of unbound-anchor root anchor is at your own risk
|
||||
# and under the terms of our LICENSE (see that file in the source).
|
||||
# auto-trust-anchor-file: "@UNBOUND_ROOTKEY_FILE@"
|
||||
|
||||
# File with DLV trusted keys. Same format as trust-anchor-file.
|
||||
# There can be only one DLV configured, it is trusted from root down.
|
||||
# Download http://ftp.isc.org/www/dlv/dlv.isc.org.key
|
||||
# dlv-anchor-file: "dlv.isc.org.key"
|
||||
|
||||
# File with trusted keys for validation. Specify more than one file
|
||||
# with several entries, one file per entry.
|
||||
# Zone file format, with DS and DNSKEY entries.
|
||||
# Note this gets out of date, use auto-trust-anchor-file please.
|
||||
# trust-anchor-file: ""
|
||||
|
||||
# Trusted key for validation. DS or DNSKEY. specify the RR on a
|
||||
# single line, surrounded by "". TTL is ignored. class is IN default.
|
||||
# Note this gets out of date, use auto-trust-anchor-file please.
|
||||
# (These examples are from August 2007 and may not be valid anymore).
|
||||
# trust-anchor: "nlnetlabs.nl. DNSKEY 257 3 5 AQPzzTWMz8qSWIQlfRnPckx2BiVmkVN6LPupO3mbz7FhLSnm26n6iG9N Lby97Ji453aWZY3M5/xJBSOS2vWtco2t8C0+xeO1bc/d6ZTy32DHchpW 6rDH1vp86Ll+ha0tmwyy9QP7y2bVw5zSbFCrefk8qCUBgfHm9bHzMG1U BYtEIQ=="
|
||||
# trust-anchor: "jelte.nlnetlabs.nl. DS 42860 5 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A"
|
||||
|
||||
# File with trusted keys for validation. Specify more than one file
|
||||
# with several entries, one file per entry. Like trust-anchor-file
|
||||
# but has a different file format. Format is BIND-9 style format,
|
||||
# the trusted-keys { name flag proto algo "key"; }; clauses are read.
|
||||
# you need external update procedures to track changes in keys.
|
||||
# trusted-keys-file: ""
|
||||
|
||||
# Ignore chain of trust. Domain is treated as insecure.
|
||||
# domain-insecure: "example.com"
|
||||
|
||||
# Override the date for validation with a specific fixed date.
|
||||
# Do not set this unless you are debugging signature inception
|
||||
# and expiration. "" or "0" turns the feature off. -1 ignores date.
|
||||
# val-override-date: ""
|
||||
|
||||
# The time to live for bogus data, rrsets and messages. This avoids
|
||||
# some of the revalidation, until the time interval expires. in secs.
|
||||
# val-bogus-ttl: 60
|
||||
|
||||
# The signature inception and expiration dates are allowed to be off
|
||||
# by 10% of the signature lifetime (expir-incep) from our local clock.
|
||||
# This leeway is capped with a minimum and a maximum. In seconds.
|
||||
# val-sig-skew-min: 3600
|
||||
# val-sig-skew-max: 86400
|
||||
|
||||
# Should additional section of secure message also be kept clean of
|
||||
# unsecure data. Useful to shield the users of this validator from
|
||||
# potential bogus data in the additional section. All unsigned data
|
||||
# in the additional section is removed from secure messages.
|
||||
# val-clean-additional: yes
|
||||
|
||||
# Turn permissive mode on to permit bogus messages. Thus, messages
|
||||
# for which security checks failed will be returned to clients,
|
||||
# instead of SERVFAIL. It still performs the security checks, which
|
||||
# result in interesting log files and possibly the AD bit in
|
||||
# replies if the message is found secure. The default is off.
|
||||
# val-permissive-mode: no
|
||||
|
||||
# Ignore the CD flag in incoming queries and refuse them bogus data.
|
||||
# Enable it if the only clients of unbound are legacy servers (w2008)
|
||||
# that set CD but cannot validate themselves.
|
||||
# ignore-cd-flag: no
|
||||
|
||||
# Have the validator log failed validations for your diagnosis.
|
||||
# 0: off. 1: A line per failed user query. 2: With reason and bad IP.
|
||||
# val-log-level: 0
|
||||
|
||||
# It is possible to configure NSEC3 maximum iteration counts per
|
||||
# keysize. Keep this table very short, as linear search is done.
|
||||
# A message with an NSEC3 with larger count is marked insecure.
|
||||
# List in ascending order the keysize and count values.
|
||||
# val-nsec3-keysize-iterations: "1024 150 2048 500 4096 2500"
|
||||
|
||||
# instruct the auto-trust-anchor-file probing to add anchors after ttl.
|
||||
# add-holddown: 2592000 # 30 days
|
||||
|
||||
# instruct the auto-trust-anchor-file probing to del anchors after ttl.
|
||||
# del-holddown: 2592000 # 30 days
|
||||
|
||||
# auto-trust-anchor-file probing removes missing anchors after ttl.
|
||||
# If the value 0 is given, missing anchors are not removed.
|
||||
# keep-missing: 31622400 # 366 days
|
||||
|
||||
# the amount of memory to use for the key cache.
|
||||
# plain value in bytes or you can append k, m or G. default is "4Mb".
|
||||
# key-cache-size: 4m
|
||||
|
||||
# the number of slabs to use for the key cache.
|
||||
# the number of slabs must be a power of 2.
|
||||
# more slabs reduce lock contention, but fragment memory usage.
|
||||
# key-cache-slabs: 4
|
||||
|
||||
# the amount of memory to use for the negative cache (used for DLV).
|
||||
# plain value in bytes or you can append k, m or G. default is "1Mb".
|
||||
# neg-cache-size: 1m
|
||||
|
||||
# a number of locally served zones can be configured.
|
||||
# local-zone: <zone> <type>
|
||||
# local-data: "<resource record string>"
|
||||
# o deny serves local data (if any), else, drops queries.
|
||||
# o refuse serves local data (if any), else, replies with error.
|
||||
# o static serves local data, else, nxdomain or nodata answer.
|
||||
# o transparent gives local data, but resolves normally for other names
|
||||
# o redirect serves the zone data for any subdomain in the zone.
|
||||
# o nodefault can be used to normally resolve AS112 zones.
|
||||
# o typetransparent resolves normally for other types and other names
|
||||
#
|
||||
# defaults are localhost address, reverse for 127.0.0.1 and ::1
|
||||
# and nxdomain for AS112 zones. If you configure one of these zones
|
||||
# the default content is omitted, or you can omit it with 'nodefault'.
|
||||
#
|
||||
# If you configure local-data without specifying local-zone, by
|
||||
# default a transparent local-zone is created for the data.
|
||||
#
|
||||
# You can add locally served data with
|
||||
# local-zone: "local." static
|
||||
# local-data: "mycomputer.local. IN A 192.0.2.51"
|
||||
# local-data: 'mytext.local TXT "content of text record"'
|
||||
#
|
||||
# You can override certain queries with
|
||||
# local-data: "adserver.example.com A 127.0.0.1"
|
||||
#
|
||||
# You can redirect a domain to a fixed address with
|
||||
# (this makes example.com, www.example.com, etc, all go to 192.0.2.3)
|
||||
# local-zone: "example.com" redirect
|
||||
# local-data: "example.com A 192.0.2.3"
|
||||
#
|
||||
# Shorthand to make PTR records, "IPv4 name" or "IPv6 name".
|
||||
# You can also add PTR records using local-data directly, but then
|
||||
# you need to do the reverse notation yourself.
|
||||
# local-data-ptr: "192.0.2.3 www.example.com"
|
||||
|
||||
# service clients over SSL (on the TCP sockets), with plain DNS inside
|
||||
# the SSL stream. Give the certificate to use and private key.
|
||||
# default is "" (disabled). requires restart to take effect.
|
||||
# ssl-service-key: "path/to/privatekeyfile.key"
|
||||
# ssl-service-pem: "path/to/publiccertfile.pem"
|
||||
# ssl-port: 443
|
||||
|
||||
# request upstream over SSL (with plain DNS inside the SSL stream).
|
||||
# Default is no. Can be turned on and off with unbound-control.
|
||||
# ssl-upstream: no
|
||||
|
||||
# Python config section. To enable:
|
||||
# o use --with-pythonmodule to configure before compiling.
|
||||
# o list python in the module-config string (above) to enable.
|
||||
# o and give a python-script to run.
|
||||
python:
|
||||
# Script file to load
|
||||
# python-script: "@UNBOUND_SHARE_DIR@/ubmodule-tst.py"
|
||||
|
||||
# Remote control config section.
|
||||
remote-control:
|
||||
# Enable remote control with unbound-control(8) here.
|
||||
# set up the keys and certificates with unbound-control-setup.
|
||||
# control-enable: no
|
||||
|
||||
# what interfaces are listened to for remote control.
|
||||
# give 0.0.0.0 and ::0 to listen to all interfaces.
|
||||
# control-interface: 127.0.0.1
|
||||
# control-interface: ::1
|
||||
|
||||
# port number for remote control operations.
|
||||
# control-port: 8953
|
||||
|
||||
# unbound server key file.
|
||||
# server-key-file: "@UNBOUND_RUN_DIR@/unbound_server.key"
|
||||
|
||||
# unbound server certificate file.
|
||||
# server-cert-file: "@UNBOUND_RUN_DIR@/unbound_server.pem"
|
||||
|
||||
# unbound-control key file.
|
||||
# control-key-file: "@UNBOUND_RUN_DIR@/unbound_control.key"
|
||||
|
||||
# unbound-control certificate file.
|
||||
# control-cert-file: "@UNBOUND_RUN_DIR@/unbound_control.pem"
|
||||
|
||||
# Stub zones.
|
||||
# Create entries like below, to make all queries for 'example.com' and
|
||||
# 'example.org' go to the given list of nameservers. list zero or more
|
||||
# nameservers by hostname or by ipaddress. If you set stub-prime to yes,
|
||||
# the list is treated as priming hints (default is no).
|
||||
# With stub-first yes, it attempts without the stub if it fails.
|
||||
# stub-zone:
|
||||
# name: "example.com"
|
||||
# stub-addr: 192.0.2.68
|
||||
# stub-prime: no
|
||||
# stub-first: no
|
||||
# stub-zone:
|
||||
# name: "example.org"
|
||||
# stub-host: ns.example.com.
|
||||
|
||||
# Forward zones
|
||||
# Create entries like below, to make all queries for 'example.com' and
|
||||
# 'example.org' go to the given list of servers. These servers have to handle
|
||||
# recursion to other nameservers. List zero or more nameservers by hostname
|
||||
# or by ipaddress. Use an entry with name "." to forward all queries.
|
||||
# If you enable forward-first, it attempts without the forward if it fails.
|
||||
# forward-zone:
|
||||
# name: "example.com"
|
||||
# forward-addr: 192.0.2.68
|
||||
# forward-addr: 192.0.2.73@5355 # forward to port 5355.
|
||||
# forward-first: no
|
||||
# forward-zone:
|
||||
# name: "example.org"
|
||||
# forward-host: fwd.example.com
|
BIN
contrib/unbound/doc/ietf67-design-02.odp
Normal file
BIN
contrib/unbound/doc/ietf67-design-02.odp
Normal file
Binary file not shown.
BIN
contrib/unbound/doc/ietf67-design-02.pdf
Normal file
BIN
contrib/unbound/doc/ietf67-design-02.pdf
Normal file
Binary file not shown.
383
contrib/unbound/doc/libunbound.3.in
Normal file
383
contrib/unbound/doc/libunbound.3.in
Normal file
@ -0,0 +1,383 @@
|
||||
.TH "libunbound" "3" "May 24, 2012" "NLnet Labs" "unbound 1.4.17"
|
||||
.\"
|
||||
.\" libunbound.3 -- unbound library functions manual
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.LP
|
||||
.B libunbound,
|
||||
.B unbound.h,
|
||||
.B ub_ctx,
|
||||
.B ub_result,
|
||||
.B ub_callback_t,
|
||||
.B ub_ctx_create,
|
||||
.B ub_ctx_delete,
|
||||
.B ub_ctx_set_option,
|
||||
.B ub_ctx_get_option,
|
||||
.B ub_ctx_config,
|
||||
.B ub_ctx_set_fwd,
|
||||
.B ub_ctx_resolvconf,
|
||||
.B ub_ctx_hosts,
|
||||
.B ub_ctx_add_ta,
|
||||
.B ub_ctx_add_ta_file,
|
||||
.B ub_ctx_trustedkeys,
|
||||
.B ub_ctx_debugout,
|
||||
.B ub_ctx_debuglevel,
|
||||
.B ub_ctx_async,
|
||||
.B ub_poll,
|
||||
.B ub_wait,
|
||||
.B ub_fd,
|
||||
.B ub_process,
|
||||
.B ub_resolve,
|
||||
.B ub_resolve_async,
|
||||
.B ub_cancel,
|
||||
.B ub_resolve_free,
|
||||
.B ub_strerror,
|
||||
.B ub_ctx_print_local_zones,
|
||||
.B ub_ctx_zone_add,
|
||||
.B ub_ctx_zone_remove,
|
||||
.B ub_ctx_data_add,
|
||||
.B ub_ctx_data_remove
|
||||
\- Unbound DNS validating resolver 1.4.17 functions.
|
||||
.SH "SYNOPSIS"
|
||||
.LP
|
||||
.B #include <unbound.h>
|
||||
.LP
|
||||
\fIstruct ub_ctx *\fR
|
||||
\fBub_ctx_create\fR(\fIvoid\fR);
|
||||
.LP
|
||||
\fIvoid\fR
|
||||
\fBub_ctx_delete\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_set_option\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR opt, \fIchar*\fR val);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_get_option\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR opt, \fIchar**\fR val);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_config\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_set_fwd\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR addr);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_resolvconf\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_hosts\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_add_ta\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR ta);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_add_ta_file\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_trustedkeys\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_debugout\fR(\fIstruct ub_ctx*\fR ctx, \fIFILE*\fR out);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_debuglevel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR d);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_async\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR dothread);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_poll\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_wait\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_fd\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_process\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_resolve\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR name,
|
||||
.br
|
||||
\fIint\fR rrtype, \fIint\fR rrclass, \fIstruct ub_result**\fR result);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_resolve_async\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR name,
|
||||
.br
|
||||
\fIint\fR rrtype, \fIint\fR rrclass, \fIvoid*\fR mydata,
|
||||
.br
|
||||
\fIub_callback_t\fR callback, \fIint*\fR async_id);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_cancel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR async_id);
|
||||
.LP
|
||||
\fIvoid\fR
|
||||
\fBub_resolve_free\fR(\fIstruct ub_result*\fR result);
|
||||
.LP
|
||||
\fIconst char *\fR
|
||||
\fBub_strerror\fR(\fIint\fR err);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_print_local_zones\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_zone_add\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR zone_name, \fIchar*\fR zone_type);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_zone_remove\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR zone_name);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_data_add\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR data);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_data_remove\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR data);
|
||||
.SH "DESCRIPTION"
|
||||
.LP
|
||||
.B Unbound
|
||||
is an implementation of a DNS resolver, that does caching and
|
||||
DNSSEC validation. This is the library API, for using the \-lunbound library.
|
||||
The server daemon is described in \fIunbound\fR(8).
|
||||
The library can be used to convert hostnames to ip addresses, and back,
|
||||
and obtain other information from the DNS. The library performs public\-key
|
||||
validation of results with DNSSEC.
|
||||
.P
|
||||
The library uses a variable of type \fIstruct ub_ctx\fR to keep context
|
||||
between calls. The user must maintain it, creating it with
|
||||
.B ub_ctx_create
|
||||
and deleting it with
|
||||
.B ub_ctx_delete\fR.
|
||||
It can be created and deleted at any time. Creating it anew removes any
|
||||
previous configuration (such as trusted keys) and clears any cached results.
|
||||
.P
|
||||
The functions are thread\-safe, and a context an be used in a threaded (as
|
||||
well as in a non\-threaded) environment. Also resolution (and validation)
|
||||
can be performed blocking and non\-blocking (also called asynchronous).
|
||||
The async method returns from the call immediately, so that processing
|
||||
can go on, while the results become available later.
|
||||
.P
|
||||
The functions are discussed in turn below.
|
||||
.SH "FUNCTIONS"
|
||||
.TP
|
||||
.B ub_ctx_create
|
||||
Create a new context, initialised with defaults.
|
||||
The information from /etc/resolv.conf and /etc/hosts is not utilised
|
||||
by default. Use
|
||||
.B ub_ctx_resolvconf
|
||||
and
|
||||
.B ub_ctx_hosts
|
||||
to read them.
|
||||
.TP
|
||||
.B ub_ctx_delete
|
||||
Delete validation context and free associated resources.
|
||||
Outstanding async queries are killed and callbacks are not called for them.
|
||||
.TP
|
||||
.B ub_ctx_set_option
|
||||
A power\-user interface that lets you specify one of the options from the
|
||||
config file format, see \fIunbound.conf\fR(5). Not all options are
|
||||
relevant. For some specific options, such as adding trust anchors, special
|
||||
routines exist. Pass the option name with the trailing ':'.
|
||||
.TP
|
||||
.B ub_ctx_get_option
|
||||
A power\-user interface that gets an option value. Some options cannot be
|
||||
gotten, and others return a newline separated list. Pass the option name
|
||||
without trailing ':'. The returned value must be free(2)d by the caller.
|
||||
.TP
|
||||
.B ub_ctx_config
|
||||
A power\-user interface that lets you specify an unbound config file, see
|
||||
\fIunbound.conf\fR(5), which is read for configuration. Not all options are
|
||||
relevant. For some specific options, such as adding trust anchors, special
|
||||
routines exist.
|
||||
.TP
|
||||
.B ub_ctx_set_fwd
|
||||
Set machine to forward DNS queries to, the caching resolver to use.
|
||||
IP4 or IP6 address. Forwards all DNS requests to that machine, which
|
||||
is expected to run a recursive resolver. If the proxy is not
|
||||
DNSSEC capable, validation may fail. Can be called several times, in
|
||||
that case the addresses are used as backup servers.
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_resolvconf
|
||||
Read list of nameservers to use from the filename given.
|
||||
Usually "/etc/resolv.conf". Uses those nameservers as caching proxies.
|
||||
If they do not support DNSSEC, validation may fail.
|
||||
Only nameservers are picked up, the searchdomain, ndots and other
|
||||
settings from \fIresolv.conf\fR(5) are ignored.
|
||||
If fname NULL is passed, "/etc/resolv.conf" is used (if on Windows,
|
||||
the system\-wide configured nameserver is picked instead).
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_hosts
|
||||
Read list of hosts from the filename given.
|
||||
Usually "/etc/hosts". When queried for, these addresses are not marked
|
||||
DNSSEC secure. If fname NULL is passed, "/etc/hosts" is used
|
||||
(if on Windows, etc/hosts from WINDIR is picked instead).
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B
|
||||
ub_ctx_add_ta
|
||||
Add a trust anchor to the given context.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
The format is a string, similar to the zone\-file format,
|
||||
[domainname] [type] [rdata contents]. Both DS and DNSKEY records are accepted.
|
||||
.TP
|
||||
.B ub_ctx_add_ta_file
|
||||
Add trust anchors to the given context.
|
||||
Pass name of a file with DS and DNSKEY records in zone file format.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_trustedkeys
|
||||
Add trust anchors to the given context.
|
||||
Pass the name of a bind\-style config file with trusted\-keys{}.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_debugout
|
||||
Set debug and error log output to the given stream. Pass NULL to disable
|
||||
output. Default is stderr. File\-names or using syslog can be enabled
|
||||
using config options, this routine is for using your own stream.
|
||||
.TP
|
||||
.B ub_ctx_debuglevel
|
||||
Set debug verbosity for the context. Output is directed to stderr.
|
||||
Higher debug level gives more output.
|
||||
.TP
|
||||
.B ub_ctx_async
|
||||
Set a context behaviour for asynchronous action.
|
||||
if set to true, enables threading and a call to
|
||||
.B ub_resolve_async
|
||||
creates a thread to handle work in the background.
|
||||
If false, a process is forked to handle work in the background.
|
||||
Changes to this setting after
|
||||
.B ub_resolve_async
|
||||
calls have been made have no effect (delete and re\-create the context
|
||||
to change).
|
||||
.TP
|
||||
.B ub_poll
|
||||
Poll a context to see if it has any new results.
|
||||
Do not poll in a loop, instead extract the fd below to poll for readiness,
|
||||
and then check, or wait using the wait routine.
|
||||
Returns 0 if nothing to read, or nonzero if a result is available.
|
||||
If nonzero, call
|
||||
.B ub_process
|
||||
to do callbacks.
|
||||
.TP
|
||||
.B ub_wait
|
||||
Wait for a context to finish with results. Calls
|
||||
.B ub_process
|
||||
after the wait for you. After the wait, there are no more outstanding
|
||||
asynchronous queries.
|
||||
.TP
|
||||
.B ub_fd
|
||||
Get file descriptor. Wait for it to become readable, at this point
|
||||
answers are returned from the asynchronous validating resolver.
|
||||
Then call the \fBub_process\fR to continue processing.
|
||||
.TP
|
||||
.B ub_process
|
||||
Call this routine to continue processing results from the validating
|
||||
resolver (when the fd becomes readable).
|
||||
Will perform necessary callbacks.
|
||||
.TP
|
||||
.B ub_resolve
|
||||
Perform resolution and validation of the target name.
|
||||
The name is a domain name in a zero terminated text string.
|
||||
The rrtype and rrclass are DNS type and class codes.
|
||||
The result structure is newly allocated with the resulting data.
|
||||
.TP
|
||||
.B ub_resolve_async
|
||||
Perform asynchronous resolution and validation of the target name.
|
||||
Arguments mean the same as for \fBub_resolve\fR except no
|
||||
data is returned immediately, instead a callback is called later.
|
||||
The callback receives a copy of the mydata pointer, that you can use to pass
|
||||
information to the callback. The callback type is a function pointer to
|
||||
a function declared as
|
||||
.IP
|
||||
void my_callback_function(void* my_arg, int err,
|
||||
.br
|
||||
struct ub_result* result);
|
||||
.IP
|
||||
The async_id is returned so you can (at your option) decide to track it
|
||||
and cancel the request if needed. If you pass a NULL pointer the async_id
|
||||
is not returned.
|
||||
.TP
|
||||
.B ub_cancel
|
||||
Cancel an async query in progress. This may return an error if the query
|
||||
does not exist, or the query is already being delivered, in that case you
|
||||
may still get a callback for the query.
|
||||
.TP
|
||||
.B ub_resolve_free
|
||||
Free struct ub_result contents after use.
|
||||
.TP
|
||||
.B ub_strerror
|
||||
Convert error value from one of the unbound library functions
|
||||
to a human readable string.
|
||||
.TP
|
||||
.B ub_ctx_print_local_zones
|
||||
Debug printout the local authority information to debug output.
|
||||
.TP
|
||||
.B ub_ctx_zone_add
|
||||
Add new zone to local authority info, like local\-zone \fIunbound.conf\fR(5)
|
||||
statement.
|
||||
.TP
|
||||
.B ub_ctx_zone_remove
|
||||
Delete zone from local authority info.
|
||||
.TP
|
||||
.B ub_ctx_data_add
|
||||
Add resource record data to local authority info, like local\-data
|
||||
\fIunbound.conf\fR(5) statement.
|
||||
.TP
|
||||
.B ub_ctx_data_remove
|
||||
Delete local authority data from the name given.
|
||||
.SH "RESULT DATA STRUCTURE"
|
||||
.LP
|
||||
The result of the DNS resolution and validation is returned as
|
||||
\fIstruct ub_result\fR. The result structure contains the following entries.
|
||||
.P
|
||||
.nf
|
||||
struct ub_result {
|
||||
char* qname; /* text string, original question */
|
||||
int qtype; /* type code asked for */
|
||||
int qclass; /* class code asked for */
|
||||
char** data; /* array of rdata items, NULL terminated*/
|
||||
int* len; /* array with lengths of rdata items */
|
||||
char* canonname; /* canonical name of result */
|
||||
int rcode; /* additional error code in case of no data */
|
||||
void* answer_packet; /* full network format answer packet */
|
||||
int answer_len; /* length of packet in octets */
|
||||
int havedata; /* true if there is data */
|
||||
int nxdomain; /* true if nodata because name does not exist */
|
||||
int secure; /* true if result is secure */
|
||||
int bogus; /* true if a security failure happened */
|
||||
char* why_bogus; /* string with error if bogus */
|
||||
};
|
||||
.fi
|
||||
.P
|
||||
If both secure and bogus are false, security was not enabled for the
|
||||
domain of the query.
|
||||
.SH "RETURN VALUES"
|
||||
Many routines return an error code. The value 0 (zero) denotes no error
|
||||
happened. Other values can be passed to
|
||||
.B ub_strerror
|
||||
to obtain a readable error string.
|
||||
.B ub_strerror
|
||||
returns a zero terminated string.
|
||||
.B ub_ctx_create
|
||||
returns NULL on an error (a malloc failure).
|
||||
.B ub_poll
|
||||
returns true if some information may be available, false otherwise.
|
||||
.B ub_fd
|
||||
returns a file descriptor or \-1 on error.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
||||
.SH "AUTHORS"
|
||||
.B Unbound
|
||||
developers are mentioned in the CREDITS file in the distribution.
|
294
contrib/unbound/doc/requirements.txt
Normal file
294
contrib/unbound/doc/requirements.txt
Normal file
@ -0,0 +1,294 @@
|
||||
Requirements for Recursive Caching Resolver
|
||||
(a.k.a. Treeshrew, Unbound-C)
|
||||
By W.C.A. Wijngaards, NLnet Labs, October 2006.
|
||||
|
||||
Contents
|
||||
1. Introduction
|
||||
2. History
|
||||
3. Goals
|
||||
4. Non-Goals
|
||||
|
||||
|
||||
1. Introduction
|
||||
---------------
|
||||
This is the requirements document for a DNS name server and aims to
|
||||
document the goals and non-goals of the project. The DNS (the Domain
|
||||
Name System) is a global, replicated database that uses a hierarchical
|
||||
structure for queries.
|
||||
|
||||
Data in the DNS is stored in Resource Record sets (RR sets), and has a
|
||||
time to live (TTL). During this time the data can be cached. It is
|
||||
thus useful to cache data to speed up future lookups. A server that
|
||||
looks up data in the DNS for clients and caches previous answers to
|
||||
speed up processing is called a caching, recursive nameserver.
|
||||
|
||||
This project aims to develop such a nameserver in modular components, so
|
||||
that also DNSSEC (secure DNS) validation and stub-resolvers (that do not
|
||||
run as a server, but a linked into an application) are easily possible.
|
||||
|
||||
The main components are the Validator that validates the security
|
||||
fingerprints on data sets, the Iterator that sends queries to the
|
||||
hierarchical DNS servers that own the data and the Cache that stores
|
||||
data from previous queries. The networking and query management code
|
||||
then interface with the modules to perform the necessary processing.
|
||||
|
||||
In Section 2 the origins of the Unbound project are documented. Section
|
||||
3 lists the goals, while Section 4 lists the explicit non-goals of the
|
||||
project. Section 5 discusses choices made during development.
|
||||
|
||||
|
||||
2. History
|
||||
----------
|
||||
The unbound resolver project started by Bill Manning, David Blacka, and
|
||||
Matt Larson (from the University of California and from Verisign), that
|
||||
created a Java based prototype resolver called Unbound. The basic
|
||||
design decisions of clean modules was executed.
|
||||
|
||||
The Java prototype worked very well, with contributions from Geoff
|
||||
Sisson and Roy Arends from Nominet. Around 2006 the idea came to create
|
||||
a full-fledged C implementation ready for deployed use. NLnet Labs
|
||||
volunteered to write this implementation.
|
||||
|
||||
|
||||
3. Goals
|
||||
--------
|
||||
o A validating recursive DNS resolver.
|
||||
o Code diversity in the DNS resolver monoculture.
|
||||
o Drop-in replacement for BIND apart from config.
|
||||
o DNSSEC support.
|
||||
o Fully RFC compliant.
|
||||
o High performance
|
||||
* even with validation.
|
||||
o Used as
|
||||
* stub resolver.
|
||||
* full caching name server.
|
||||
* resolver library.
|
||||
o Elegant design of validator, resolver, cache modules.
|
||||
* provide the ability to pick and choose modules.
|
||||
o Robust.
|
||||
o In C, open source: The BSD license.
|
||||
o Highly portable, targets include modern Unix systems, such as *BSD,
|
||||
solaris, linux, and maybe also the windows platform.
|
||||
o Smallest as possible component that does the job.
|
||||
o Stub-zones can be configured (local data or AS112 zones).
|
||||
|
||||
|
||||
4. Non-Goals
|
||||
------------
|
||||
o An authoritative name server.
|
||||
o Too many Features.
|
||||
|
||||
|
||||
5. Choices
|
||||
----------
|
||||
o rfc2181 decourages duplicates RRs in RRsets. unbound does not create
|
||||
duplicates, but when presented with duplicates on the wire from the
|
||||
authoritative servers, does not perform duplicate removal.
|
||||
It does do some rrsig duplicate removal, in the msgparser, for dnssec qtype
|
||||
rrsig and any, because of special rrsig processing in the msgparser.
|
||||
o The harden-glue feature, when yes all out of zone glue is deleted, when
|
||||
no out of zone glue is used for further resolving, is more complicated
|
||||
than that, see below.
|
||||
Main points:
|
||||
* rfc2182 trust handling is used.
|
||||
* data is let through only in very specific cases
|
||||
* spoofability remains possible.
|
||||
Not all glue is let through (despite the name of the option). Only glue
|
||||
which is present in a delegation, of type A and AAAA, where the name is
|
||||
present in the NS record in the authority section is let through.
|
||||
The glue that is let through is stored in the cache (marked as 'from the
|
||||
additional section'). And will then be used for sending queries to. It
|
||||
will not be present in the reply to the client (if RD is off).
|
||||
A direct query for that name will attempt to get a msg into the message
|
||||
cache. Since A and AAAA queries are not synthesized by the unbound cache,
|
||||
this query will be (eventually) sent to the authoritative server and its
|
||||
answer will be put in the cache, marked as 'from the answer section' and
|
||||
thus remove the 'from the additional section' data, and this record is
|
||||
returned to the client.
|
||||
The message has a TTL smaller or equal to the TTL of the answer RR.
|
||||
If the cache memory is low; the answer RR may be dropped, and a glue
|
||||
RR may be inserted, within the message TTL time, and thus return the
|
||||
spoofed glue to a client. When the message expires, it is refetched and
|
||||
the cached RR is updated with the correct content.
|
||||
The server can be spoofed by getting it to visit a especially prepared
|
||||
domain. This domain then inserts an address for another authoritative
|
||||
server into the cache, when visiting that other domain, this address may
|
||||
then be used to send queries to. And fake answers may be returned.
|
||||
If the other domain is signed by DNSSEC, the fakes will be detected.
|
||||
|
||||
In summary, the harden glue feature presents a security risk if
|
||||
disabled. Disabling the feature leads to possible better performance
|
||||
as more glue is present for the recursive service to use. The feature
|
||||
is implemented so as to minimise the security risk, while trying to
|
||||
keep this performance gain.
|
||||
o The method by which dnssec-lameness is detected is not secure. DNSSEC lame
|
||||
is when a server has the zone in question, but lacks dnssec data, such as
|
||||
signatures. The method to detect dnssec lameness looks at nonvalidated
|
||||
data from the parent of a zone. This can be used, by spoofing the parent,
|
||||
to create a false sense of dnssec-lameness in the child, or a false sense
|
||||
or dnssec-non-lameness in the child. The first results in the server marked
|
||||
lame, and not used for 900 seconds, and the second will result in a
|
||||
validator failure (SERVFAIL again), when the query is validated later on.
|
||||
|
||||
Concluding, a spoof of the parent delegation can be used for many cases
|
||||
of denial of service. I.e. a completely different NS set could be returned,
|
||||
or the information withheld. All of these alterations can be caught by
|
||||
the validator if the parent is signed, and result in 900 seconds bogus.
|
||||
The dnssec-lameness detection is used to detect operator failures,
|
||||
before the validator will properly verify the messages.
|
||||
|
||||
Also for zones for which no chain of trust exists, but a DS is given by the
|
||||
parent, dnssec-lameness detection enables. This delivers dnssec to our
|
||||
clients when possible (for client validators).
|
||||
|
||||
The following issue needs to be resolved:
|
||||
a server that serves both a parent and child zone, where
|
||||
parent is signed, but child is not. The server must not be marked
|
||||
lame for the parent zone, because the child answer is not signed.
|
||||
Instead of a false positive, we want false negatives; failure to
|
||||
detect dnssec-lameness is less of a problem than marking honest
|
||||
servers lame. dnssec-lameness is a config error and deserves the trouble.
|
||||
So, only messages that identify the zone are used to mark the zone
|
||||
lame. The zone is identified by SOA or NS RRsets in the answer/auth.
|
||||
That includes almost all negative responses and also A, AAAA qtypes.
|
||||
That would be most responses from servers.
|
||||
For referrals, delegations that add a single label can be checked to be
|
||||
from their zone, this covers most delegation-centric zones.
|
||||
|
||||
So possibly, for complicated setups, with multiple (parent-child) zones
|
||||
on a server, dnssec-lameness detection does not work - no dnssec-lameness
|
||||
is detected. Instead the zone that is dnssec-lame becomes bogus.
|
||||
|
||||
o authority features.
|
||||
This is a recursive server, and authority features are out of scope.
|
||||
However, some authority features are expected in a recursor. Things like
|
||||
localhost, reverse lookup for 127.0.0.1, or blocking AS112 traffic.
|
||||
Also redirection of domain names with fixed data is needed by service
|
||||
providers. Limited support is added specifically to address this.
|
||||
|
||||
Adding full authority support, requires much more code, and more complex
|
||||
maintenance.
|
||||
|
||||
The limited support allows adding some static data (for localhost and so),
|
||||
and to respond with a fixed rcode (NXDOMAIN) for domains (such as AS112).
|
||||
|
||||
You can put authority data on a separate server, and set the server in
|
||||
unbound.conf as stub for those zones, this allows clients to access data
|
||||
from the server without making unbound authoritative for the zones.
|
||||
|
||||
o the access control denies queries before any other processing.
|
||||
This denies queries that are not authoritative, or version.bind, or any.
|
||||
And thus prevents cache-snooping (denied hosts cannot make non-recursive
|
||||
queries and get answers from the cache).
|
||||
|
||||
o If a client makes a query without RD bit, in the case of a returned
|
||||
message from cache which is:
|
||||
answer section: empty
|
||||
auth section: NS record present, no SOA record, no DS record,
|
||||
maybe NSEC or NSEC3 records present.
|
||||
additional: A records or other relevant records.
|
||||
A SOA record would indicate that this was a NODATA answer.
|
||||
A DS records would indicate a referral.
|
||||
Absence of NS record would indicate a NODATA answer as well.
|
||||
|
||||
Then the receiver does not know whether this was a referral
|
||||
with attempt at no-DS proof) or a nodata answer with attempt
|
||||
at no-data proof. It could be determined by attempting to prove
|
||||
either condition; and looking if only one is valid, but both
|
||||
proofs could be valid, or neither could be valid, which creates
|
||||
doubt. This case is validated by unbound as a 'referral' which
|
||||
ascertains that RRSIGs are OK (and not omitted), but does not
|
||||
check NSEC/NSEC3.
|
||||
|
||||
o Case preservation
|
||||
Unbound preserves the casing received from authority servers as best
|
||||
as possible. It compresses without case, so case can get lost there.
|
||||
The casing from the query name is used in preference to the casing
|
||||
of the authority server. This is the same as BIND. RFC4343 allows either
|
||||
behaviour.
|
||||
|
||||
o Denial of service protection
|
||||
If many queries are made, and they are made to names for which the
|
||||
authority servers do not respond, then the requestlist for unbound
|
||||
fills up fast. This results in denial of service for new queries.
|
||||
To combat this the first 50% of the requestlist can run to completion.
|
||||
The last 50% of the requestlist get (200 msec) at least and are replaced
|
||||
by newer queries when older (LIFO).
|
||||
When a new query comes in, and a place in the first 50% is available, this
|
||||
is preferred. Otherwise, it can replace older queries out of the last 50%.
|
||||
Thus, even long queries get a 50% chance to be resolved. And many 'short'
|
||||
one or two round-trip resolves can be done in the last 50% of the list.
|
||||
The timeout can be configured.
|
||||
|
||||
o EDNS fallback. Is done according to the EDNS RFC (and update draft-00).
|
||||
Unbound assumes EDNS 0 support for the first query. Then it can detect
|
||||
support (if the servers replies) or non-support (on a NOTIMPL or FORMERR).
|
||||
Some middleboxes drop EDNS 0 queries, mainly when forwarding, not when
|
||||
routing packets. To detect this, when timeouts keep happening, as the
|
||||
timeout approached 5-10 seconds, and EDNS status has not been detected yet,
|
||||
a single probe query is sent. This probe has a sub-second timeout, and
|
||||
if the server responds (quickly) without EDNS, this is cached for 15 min.
|
||||
This works very well when detecting an address that you use much - like
|
||||
a forwarder address - which is where the middleboxes need to be detected.
|
||||
Otherwise, it results in a 5 second wait time before EDNS timeout is
|
||||
detected, which is slow but it works at least.
|
||||
It minimizes the chances of a dropped query making a (DNSSEC) EDNS server
|
||||
falsely EDNS-nonsupporting, and thus DNSSEC-bogus, works well with
|
||||
middleboxes, and can detect the occasional authority that drops EDNS.
|
||||
For some boxes it is necessary to probe for every failing query, a
|
||||
reassurance that the DNS server does EDNS does not mean that path can
|
||||
take large DNS answers.
|
||||
|
||||
o 0x20 backoff.
|
||||
The draft describes to back off to the next server, and go through all
|
||||
servers several times. Unbound goes on get the full list of nameserver
|
||||
addresses, and then makes 3 * number of addresses queries.
|
||||
They are sent to a random server, but no one address more than 4 times.
|
||||
It succeeds if one has 0x20 intact, or else all are equal.
|
||||
Otherwise, servfail is returned to the client.
|
||||
|
||||
o NXDOMAIN and SOA serial numbers.
|
||||
Unbound keeps TTL values for message formats, and thus rcodes, such
|
||||
as NXDOMAIN. Also it keeps the latest rrsets in the rrset cache.
|
||||
So it will faithfully negative cache for the exact TTL as originally
|
||||
specified for an NXDOMAIN message, but send a newer SOA record if
|
||||
this has been found in the mean time. In point, this could lead to a
|
||||
negative cached NXDOMAIN reply with a SOA RR where the serial number
|
||||
indicates a zone version where this domain is not any longer NXDOMAIN.
|
||||
These situations become consistent once the original TTL expires.
|
||||
If the domain is DNSSEC signed, by the way, then NSEC records are
|
||||
updated more carefully. If one of the NSEC records in an NXDOMAIN is
|
||||
updated from another query, the NXDOMAIN is dropped from the cache,
|
||||
and queried for again, so that its proof can be checked again.
|
||||
|
||||
o SOA records in negative cached answers for DS queries.
|
||||
The current unbound code uses a negative cache for queries for type DS.
|
||||
This speeds up building chains of trust, and uses NSEC and NSEC3
|
||||
(optout) information to speed up lookups. When used internally,
|
||||
the bare NSEC(3) information is sufficient, probably picked up from
|
||||
a referral. When answering to clients, a SOA record is needed for
|
||||
the correct message format, a SOA record is picked from the cache
|
||||
(and may not actually match the serial number of the SOA for which the
|
||||
NSEC and NSEC3 records were obtained) if available otherwise network
|
||||
queries are performed to get the data.
|
||||
|
||||
o Parent and child with different nameserver information.
|
||||
A misconfiguration that sometimes happens is where the parent and child
|
||||
have different NS, glue information. The child is authoritative, and
|
||||
unbound will not trust information from the parent nameservers as the
|
||||
final answer. To help lookups, unbound will however use the parent-side
|
||||
version of the glue as a last resort lookup. This resolves lookups for
|
||||
those misconfigured domains where the servers reported by the parent
|
||||
are the only ones working, and servers reported by the child do not.
|
||||
|
||||
o Failure of validation and probing.
|
||||
Retries on a validation failure are now 5x to a different nameserver IP
|
||||
(if possible), and then it gives up, for one name, type, class entry in
|
||||
the message cache. If a DNSKEY or DS fails in the chain of trust in the
|
||||
key cache additionally, after the probing, a bad key entry is created that
|
||||
makes the entire zone bogus for 900 seconds. This is a fixed value at
|
||||
this time and is conservative in sending probes. It makes the compound
|
||||
effect of many resolvers less and easier to handle, but penalizes
|
||||
individual resolvers by having less probes and a longer time before fixes
|
||||
are picked up.
|
||||
|
174
contrib/unbound/doc/unbound-anchor.8.in
Normal file
174
contrib/unbound/doc/unbound-anchor.8.in
Normal file
@ -0,0 +1,174 @@
|
||||
.TH "unbound-anchor" "8" "May 24, 2012" "NLnet Labs" "unbound 1.4.17"
|
||||
.\"
|
||||
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
|
||||
.\"
|
||||
.\" Copyright (c) 2008, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.LP
|
||||
.B unbound\-anchor
|
||||
\- Unbound anchor utility.
|
||||
.SH "SYNOPSIS"
|
||||
.B unbound\-anchor
|
||||
.RB [ opts ]
|
||||
.SH "DESCRIPTION"
|
||||
.B Unbound\-anchor
|
||||
performs setup or update of the root trust anchor for DNSSEC validation.
|
||||
It can be run (as root) from the commandline, or run as part of startup
|
||||
scripts. Before you start the \fIunbound\fR(8) DNS server.
|
||||
.P
|
||||
Suggested usage:
|
||||
.P
|
||||
.nf
|
||||
# in the init scripts.
|
||||
# provide or update the root anchor (if necessary)
|
||||
unbound-anchor -a "@UNBOUND_ROOTKEY_FILE@"
|
||||
# Please note usage of this root anchor is at your own risk
|
||||
# and under the terms of our LICENSE (see source).
|
||||
#
|
||||
# start validating resolver
|
||||
# the unbound.conf contains:
|
||||
# auto-trust-anchor-file: "@UNBOUND_ROOTKEY_FILE@"
|
||||
unbound -c unbound.conf
|
||||
.fi
|
||||
.P
|
||||
This tool provides builtin default contents for the root anchor and root
|
||||
update certificate files.
|
||||
.P
|
||||
It tests if the root anchor file works, and if not, and an update is possible,
|
||||
attempts to update the root anchor using the root update certificate.
|
||||
It performs a https fetch of root-anchors.xml and checks the results, if
|
||||
all checks are successful, it updates the root anchor file. Otherwise
|
||||
the root anchor file is unchanged. It performs RFC5011 tracking if the
|
||||
DNSSEC information available via the DNS makes that possible.
|
||||
.P
|
||||
If does not perform an update if the certificate is expired, if the network
|
||||
is down or other errors occur.
|
||||
.P
|
||||
The available options are:
|
||||
.TP
|
||||
.B \-a \fIfile
|
||||
The root anchor key file, that is read in and written out.
|
||||
Default is @UNBOUND_ROOTKEY_FILE@.
|
||||
If the file does not exist, or is empty, a builtin root key is written to it.
|
||||
.TP
|
||||
.B \-c \fIfile
|
||||
The root update certificate file, that is read in.
|
||||
Default is @UNBOUND_ROOTCERT_FILE@.
|
||||
If the file does not exist, or is empty, a builtin certificate is used.
|
||||
.TP
|
||||
.B \-l
|
||||
List the builtin root key and builtin root update certificate on stdout.
|
||||
.TP
|
||||
.B \-u \fIname
|
||||
The server name, it connects to https://name. Specify without https:// prefix.
|
||||
The default is "data.iana.org". It connects to the port specified with \-P.
|
||||
You can pass an IPv4 addres or IPv6 address (no brackets) if you want.
|
||||
.TP
|
||||
.B \-x \fIpath
|
||||
The pathname to the root\-anchors.xml file on the server. (forms URL with \-u).
|
||||
The default is /root\-anchors/root\-anchors.xml.
|
||||
.TP
|
||||
.B \-s \fIpath
|
||||
The pathname to the root\-anchors.p7s file on the server. (forms URL with \-u).
|
||||
The default is /root\-anchors/root\-anchors.p7s. This file has to be a PKCS7
|
||||
signature over the xml file, using the pem file (\-c) as trust anchor.
|
||||
.TP
|
||||
.B \-4
|
||||
Use IPv4 for domain resolution and contacting the server on https. Default is
|
||||
to use IPv4 and IPv6 where appropriate.
|
||||
.TP
|
||||
.B \-6
|
||||
Use IPv6 for domain resolution and contacting the server on https. Default is
|
||||
to use IPv4 and IPv6 where appropriate.
|
||||
.TP
|
||||
.B \-f \fIresolv.conf
|
||||
Use the given resolv.conf file. Not enabled by default, but you could try to
|
||||
pass /etc/resolv.conf on some systems. It contains the IP addresses of the
|
||||
recursive nameservers to use. However, since this tool could be used to
|
||||
bootstrap that very recursive nameserver, it would not be useful (since
|
||||
that server is not up yet, since we are bootstrapping it). It could be
|
||||
useful in a situation where you know an upstream cache is deployed (and
|
||||
running) and in captive portal situations.
|
||||
.TP
|
||||
.B \-r \fIroot.hints
|
||||
Use the given root.hints file (same syntax as the BIND and Unbound root hints
|
||||
file) to bootstrap domain resolution. By default a list of builtin root
|
||||
hints is used. Unbound\-anchor goes to the network itself for these roots,
|
||||
to resolve the server (\-u option) and to check the root DNSKEY records.
|
||||
It does so, because the tool when used for bootstrapping the recursive
|
||||
resolver, cannot use that recursive resolver itself because it is bootstrapping
|
||||
that server.
|
||||
.TP
|
||||
.B \-v
|
||||
More verbose. Once prints informational messages, multiple times may enable
|
||||
large debug amounts (such as full certificates or byte\-dumps of downloaded
|
||||
files). By default it prints almost nothing. It also prints nothing on
|
||||
errors by default; in that case the original root anchor file is simply
|
||||
left undisturbed, so that a recursive server can start right after it.
|
||||
.TP
|
||||
.B \-C \fIunbound.conf
|
||||
Debug option to read unbound.conf into the resolver process used.
|
||||
.TP
|
||||
.B \-P \fIport
|
||||
Set the port number to use for the https connection. The default is 443.
|
||||
.TP
|
||||
.B \-F
|
||||
Debug option to force update of the root anchor through downloading the xml
|
||||
file and verifying it with the certificate. By default it first tries to
|
||||
update by contacting the DNS, which uses much less bandwidth, is much
|
||||
faster (200 msec not 2 sec), and is nicer to the deployed infrastructure.
|
||||
With this option, it still attempts to do so (and may verbosely tell you),
|
||||
but then ignores the result and goes on to use the xml fallback method.
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.TP
|
||||
.B \-v
|
||||
More verbose. Prints output detailing what happens.
|
||||
.SH "EXIT CODE"
|
||||
This tool exits with value 1 if the root anchor was updated using the
|
||||
certificate or if the builtin root-anchor was used. It exits with code
|
||||
0 if no update was necessary, if the update was possible with RFC5011
|
||||
tracking, or if an error occurred.
|
||||
.P
|
||||
You can check the exit value in this manner:
|
||||
.nf
|
||||
unbound-anchor -a "root.key" || logger "Please check root.key"
|
||||
.fi
|
||||
Or something more suitable for your operational environment.
|
||||
.SH "TRUST"
|
||||
The root keys and update certificate included in this tool
|
||||
are provided for convenience and under the terms of our
|
||||
license (see the LICENSE file in the source distribution or
|
||||
http://unbound.nlnetlabs.nl/svn/trunk/LICENSE) and might be stale or
|
||||
not suitable to your purpose.
|
||||
.P
|
||||
By running "unbound\-anchor \-l" the keys and certificate that are
|
||||
configured in the code are printed for your convenience.
|
||||
.P
|
||||
The build\-in configuration can be overridden by providing a root\-cert
|
||||
file and a rootkey file.
|
||||
.SH "FILES"
|
||||
.TP
|
||||
.I @UNBOUND_ROOTKEY_FILE@
|
||||
The root anchor file, updated with 5011 tracking, and read and written to.
|
||||
The file is created if it does not exist.
|
||||
.TP
|
||||
.I @UNBOUND_ROOTCERT_FILE@
|
||||
The trusted self\-signed certificate that is used to verify the downloaded
|
||||
DNSSEC root trust anchor. You can update it by fetching it from
|
||||
https://data.iana.org/root\-anchors/icannbundle.pem (and validate it).
|
||||
If the file does not exist or is empty, a builtin version is used.
|
||||
.TP
|
||||
.I https://data.iana.org/root\-anchors/root\-anchors.xml
|
||||
Source for the root key information.
|
||||
.TP
|
||||
.I https://data.iana.org/root\-anchors/root\-anchors.p7s
|
||||
Signature on the root key information.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
49
contrib/unbound/doc/unbound-checkconf.8.in
Normal file
49
contrib/unbound/doc/unbound-checkconf.8.in
Normal file
@ -0,0 +1,49 @@
|
||||
.TH "unbound-checkconf" "8" "May 24, 2012" "NLnet Labs" "unbound 1.4.17"
|
||||
.\"
|
||||
.\" unbound-checkconf.8 -- unbound configuration checker manual
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.LP
|
||||
unbound\-checkconf
|
||||
\- Check unbound configuration file for errors.
|
||||
.SH "SYNOPSIS"
|
||||
.B unbound\-checkconf
|
||||
.RB [ \-h ]
|
||||
.RB [ \-o
|
||||
.IR option ]
|
||||
.RI [ cfgfile ]
|
||||
.SH "DESCRIPTION"
|
||||
.B Unbound\-checkconf
|
||||
checks the configuration file for the
|
||||
\fIunbound\fR(8)
|
||||
DNS resolver for syntax and other errors.
|
||||
The config file syntax is described in
|
||||
\fIunbound.conf\fR(5).
|
||||
.P
|
||||
The available options are:
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.TP
|
||||
.B \-o\fI option
|
||||
If given, after checking the config file the value of this option is
|
||||
printed to stdout. For "" (disabled) options an empty line is printed.
|
||||
.TP
|
||||
.I cfgfile
|
||||
The config file to read with settings for unbound. It is checked.
|
||||
If omitted, the config file at the default location is checked.
|
||||
.SH "EXIT CODE"
|
||||
The unbound\-checkconf program exits with status code 1 on error,
|
||||
0 for a correct config file.
|
||||
.SH "FILES"
|
||||
.TP
|
||||
.I @ub_conf_file@
|
||||
unbound configuration file.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
450
contrib/unbound/doc/unbound-control.8.in
Normal file
450
contrib/unbound/doc/unbound-control.8.in
Normal file
@ -0,0 +1,450 @@
|
||||
.TH "unbound-control" "8" "May 24, 2012" "NLnet Labs" "unbound 1.4.17"
|
||||
.\"
|
||||
.\" unbound-control.8 -- unbound remote control manual
|
||||
.\"
|
||||
.\" Copyright (c) 2008, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.LP
|
||||
.B unbound\-control,
|
||||
.B unbound\-control\-setup
|
||||
\- Unbound remote server control utility.
|
||||
.SH "SYNOPSIS"
|
||||
.B unbound\-control
|
||||
.RB [ \-h ]
|
||||
.RB [ \-c
|
||||
.IR cfgfile ]
|
||||
.RB [ \-s
|
||||
.IR server ]
|
||||
.IR command
|
||||
.SH "DESCRIPTION"
|
||||
.B Unbound\-control
|
||||
performs remote administration on the \fIunbound\fR(8) DNS server.
|
||||
It reads the configuration file, contacts the unbound server over SSL
|
||||
sends the command and displays the result.
|
||||
.P
|
||||
The available options are:
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.TP
|
||||
.B \-c \fIcfgfile
|
||||
The config file to read with settings. If not given the default
|
||||
config file @ub_conf_file@ is used.
|
||||
.TP
|
||||
.B \-s \fIserver[@port]
|
||||
IPv4 or IPv6 address of the server to contact. If not given, the
|
||||
address is read from the config file.
|
||||
.SH "COMMANDS"
|
||||
There are several commands that the server understands.
|
||||
.TP
|
||||
.B start
|
||||
Start the server. Simply execs \fIunbound\fR(8). The unbound executable
|
||||
is searched for in the \fBPATH\fR set in the environment. It is started
|
||||
with the config file specified using \fI\-c\fR or the default config file.
|
||||
.TP
|
||||
.B stop
|
||||
Stop the server. The server daemon exits.
|
||||
.TP
|
||||
.B reload
|
||||
Reload the server. This flushes the cache and reads the config file fresh.
|
||||
.TP
|
||||
.B verbosity \fInumber
|
||||
Change verbosity value for logging. Same values as \fBverbosity\fR keyword in
|
||||
\fIunbound.conf\fR(5). This new setting lasts until the server is issued
|
||||
a reload (taken from config file again), or the next verbosity control command.
|
||||
.TP
|
||||
.B log_reopen
|
||||
Reopen the logfile, close and open it. Useful for logrotation to make the
|
||||
daemon release the file it is logging to. If you are using syslog it will
|
||||
attempt to close and open the syslog (which may not work if chrooted).
|
||||
.TP
|
||||
.B stats
|
||||
Print statistics. Resets the internal counters to zero, this can be
|
||||
controlled using the \fBstatistics\-cumulative\fR config statement.
|
||||
Statistics are printed with one [name]: [value] per line.
|
||||
.TP
|
||||
.B stats_noreset
|
||||
Peek at statistics. Prints them like the \fBstats\fR command does, but does not
|
||||
reset the internal counters to zero.
|
||||
.TP
|
||||
.B status
|
||||
Display server status. Exit code 3 if not running (the connection to the
|
||||
port is refused), 1 on error, 0 if running.
|
||||
.TP
|
||||
.B local_zone \fIname\fR \fItype
|
||||
Add new local zone with name and type. Like \fBlocal\-zone\fR config statement.
|
||||
If the zone already exists, the type is changed to the given argument.
|
||||
.TP
|
||||
.B local_zone_remove \fIname
|
||||
Remove the local zone with the given name. Removes all local data inside
|
||||
it. If the zone does not exist, the command succeeds.
|
||||
.TP
|
||||
.B local_data \fIRR data...
|
||||
Add new local data, the given resource record. Like \fBlocal\-data\fR
|
||||
config statement, except for when no covering zone exists. In that case
|
||||
this remote control command creates a transparent zone with the same
|
||||
name as this record. This command is not good at returning detailed syntax
|
||||
errors.
|
||||
.TP
|
||||
.B local_data_remove \fIname
|
||||
Remove all RR data from local name. If the name already has no items,
|
||||
nothing happens. Often results in NXDOMAIN for the name (in a static zone),
|
||||
but if the name has become an empty nonterminal (there is still data in
|
||||
domain names below the removed name), NOERROR nodata answers are the
|
||||
result for that name.
|
||||
.TP
|
||||
.B dump_cache
|
||||
The contents of the cache is printed in a text format to stdout. You can
|
||||
redirect it to a file to store the cache in a file.
|
||||
.TP
|
||||
.B load_cache
|
||||
The contents of the cache is loaded from stdin. Uses the same format as
|
||||
dump_cache uses. Loading the cache with old, or wrong data can result
|
||||
in old or wrong data returned to clients. Loading data into the cache
|
||||
in this way is supported in order to aid with debugging.
|
||||
.TP
|
||||
.B lookup \fIname
|
||||
Print to stdout the name servers that would be used to look up the
|
||||
name specified.
|
||||
.TP
|
||||
.B flush \fIname
|
||||
Remove the name from the cache. Removes the types
|
||||
A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV and NAPTR.
|
||||
Because that is fast to do. Other record types can be removed using
|
||||
.B flush_type
|
||||
or
|
||||
.B flush_zone\fR.
|
||||
.TP
|
||||
.B flush_type \fIname\fR \fItype
|
||||
Remove the name, type information from the cache.
|
||||
.TP
|
||||
.B flush_zone \fIname
|
||||
Remove all information at or below the name from the cache.
|
||||
The rrsets and key entries are removed so that new lookups will be performed.
|
||||
This needs to walk and inspect the entire cache, and is a slow operation.
|
||||
.TP
|
||||
.B flush_stats
|
||||
Reset statistics to zero.
|
||||
.TP
|
||||
.B flush_requestlist
|
||||
Drop the queries that are worked on. Stops working on the queries that the
|
||||
server is working on now. The cache is unaffected. No reply is sent for
|
||||
those queries, probably making those users request again later.
|
||||
Useful to make the server restart working on queries with new settings,
|
||||
such as a higher verbosity level.
|
||||
.TP
|
||||
.B dump_requestlist
|
||||
Show what is worked on. Prints all queries that the server is currently
|
||||
working on. Prints the time that users have been waiting. For internal
|
||||
requests, no time is printed. And then prints out the module status.
|
||||
.TP
|
||||
.B flush_infra \fIall|IP
|
||||
If all then entire infra cache is emptied. If a specific IP address, the
|
||||
entry for that address is removed from the cache. It contains EDNS, ping
|
||||
and lameness data.
|
||||
.TP
|
||||
.B dump_infra
|
||||
Show the contents of the infra cache.
|
||||
.TP
|
||||
.B set_option \fIopt: val
|
||||
Set the option to the given value without a reload. The cache is
|
||||
therefore not flushed. The option must end with a ':' and whitespace
|
||||
must be between the option and the value. Some values may not have an
|
||||
effect if set this way, the new values are not written to the config file,
|
||||
not all options are supported. This is different from the set_option call
|
||||
in libunbound, where all values work because unbound has not been inited.
|
||||
.IP
|
||||
The values that work are: statistics\-interval, statistics\-cumulative,
|
||||
do\-not\-query\-localhost, harden\-short\-bufsize, harden\-large\-queries,
|
||||
harden\-glue, harden\-dnssec\-stripped, harden\-below\-nxdomain,
|
||||
harden\-referral\-path, prefetch, prefetch\-key, log\-queries,
|
||||
hide\-identity, hide\-version, identity, version, val\-log\-level,
|
||||
val\-log\-squelch, ignore\-cd\-flag, add\-holddown, del\-holddown,
|
||||
keep\-missing, tcp\-upstream, ssl\-upstream.
|
||||
.TP
|
||||
.B get_option \fIopt
|
||||
Get the value of the option. Give the option name without a trailing ':'.
|
||||
The value is printed. If the value is "", nothing is printed
|
||||
and the connection closes. On error 'error ...' is printed (it gives
|
||||
a syntax error on unknown option). For some options a list of values,
|
||||
one on each line, is printed. The options are shown from the config file
|
||||
as modified with set_option. For some options an override may have been
|
||||
taken that does not show up with this command, not results from e.g. the
|
||||
verbosity and forward control commands. Not all options work, see list_stubs,
|
||||
list_forwards, list_local_zones and list_local_data for those.
|
||||
.TP
|
||||
.B list_stubs
|
||||
List the stub zones in use. These are printed one by one to the output.
|
||||
This includes the root hints in use.
|
||||
.TP
|
||||
.B list_forwards
|
||||
List the forward zones in use. These are printed zone by zone to the output.
|
||||
.TP
|
||||
.B list_local_zones
|
||||
List the local zones in use. These are printed one per line with zone type.
|
||||
.TP
|
||||
.B list_local_data
|
||||
List the local data RRs in use. The resource records are printed.
|
||||
.TP
|
||||
.B forward_add \fR[\fI+i\fR] \fIzone addr ...
|
||||
Add a new forward zone to running unbound. With +i option also adds a
|
||||
\fIdomain\-insecure\fR for the zone (so it can resolve insecurely if you have
|
||||
a DNSSEC root trust anchor configured for other names).
|
||||
The addr can be IP4, IP6 or nameserver names, like \fIforward-zone\fR config
|
||||
in unbound.conf.
|
||||
.TP
|
||||
.B forward_remove \fR[\fI+i\fR] \fIzone
|
||||
Remove a forward zone from running unbound. The +i also removes a
|
||||
\fIdomain\-insecure\fR for the zone.
|
||||
.TP
|
||||
.B stub_add \fR[\fI+ip\fR] \fIzone addr ...
|
||||
Add a new stub zone to running unbound. With +i option also adds a
|
||||
\fIdomain\-insecure\fR for the zone. With +p the stub zone is set to prime,
|
||||
without it it is set to notprime. The addr can be IP4, IP6 or nameserver
|
||||
names, like the \fIstub-zone\fR config in unbound.conf.
|
||||
.TP
|
||||
.B stub_remove \fR[\fI+i\fR] \fIzone
|
||||
Remove a stub zone from running unbound. The +i also removes a
|
||||
\fIdomain\-insecure\fR for the zone.
|
||||
.TP
|
||||
.B forward \fR[\fIoff\fR | \fIaddr ...\fR ]
|
||||
Setup forwarding mode. Configures if the server should ask other upstream
|
||||
nameservers, should go to the internet root nameservers itself, or show
|
||||
the current config. You could pass the nameservers after a DHCP update.
|
||||
.IP
|
||||
Without arguments the current list of addresses used to forward all queries
|
||||
to is printed. On startup this is from the forward\-zone "." configuration.
|
||||
Afterwards it shows the status. It prints off when no forwarding is used.
|
||||
.IP
|
||||
If \fIoff\fR is passed, forwarding is disabled and the root nameservers
|
||||
are used. This can be used to avoid to avoid buggy or non\-DNSSEC supporting
|
||||
nameservers returned from DHCP. But may not work in hotels or hotspots.
|
||||
.IP
|
||||
If one or more IPv4 or IPv6 addresses are given, those are then used to forward
|
||||
queries to. The addresses must be separated with spaces. With '@port' the
|
||||
port number can be set explicitly (default port is 53 (DNS)).
|
||||
.IP
|
||||
By default the forwarder information from the config file for the root "." is
|
||||
used. The config file is not changed, so after a reload these changes are
|
||||
gone. Other forward zones from the config file are not affected by this command.
|
||||
.SH "EXIT CODE"
|
||||
The unbound\-control program exits with status code 1 on error, 0 on success.
|
||||
.SH "SET UP"
|
||||
The setup requires a self\-signed certificate and private keys for both
|
||||
the server and client. The script \fIunbound\-control\-setup\fR generates
|
||||
these in the default run directory, or with \-d in another directory.
|
||||
If you change the access control permissions on the key files you can decide
|
||||
who can use unbound\-control, by default owner and group but not all users.
|
||||
Run the script under the same username as you have configured in unbound.conf
|
||||
or as root, so that the daemon is permitted to read the files, for example with:
|
||||
.nf
|
||||
sudo \-u unbound unbound\-control\-setup
|
||||
.fi
|
||||
If you have not configured
|
||||
a username in unbound.conf, the keys need read permission for the user
|
||||
credentials under which the daemon is started.
|
||||
The script preserves private keys present in the directory.
|
||||
After running the script as root, turn on \fBcontrol\-enable\fR in
|
||||
\fIunbound.conf\fR.
|
||||
.SH "STATISTIC COUNTERS"
|
||||
The \fIstats\fR command shows a number of statistic counters.
|
||||
.TP
|
||||
.I threadX.num.queries
|
||||
number of queries received by thread
|
||||
.TP
|
||||
.I threadX.num.cachehits
|
||||
number of queries that were successfully answered using a cache lookup
|
||||
.TP
|
||||
.I threadX.num.cachemiss
|
||||
number of queries that needed recursive processing
|
||||
.TP
|
||||
.I threadX.num.prefetch
|
||||
number of cache prefetches performed. This number is included in
|
||||
cachehits, as the original query had the unprefetched answer from cache,
|
||||
and resulted in recursive processing, taking a slot in the requestlist.
|
||||
Not part of the recursivereplies (or the histogram thereof) or cachemiss,
|
||||
as a cache response was sent.
|
||||
.TP
|
||||
.I threadX.num.recursivereplies
|
||||
The number of replies sent to queries that needed recursive processing. Could be smaller than threadX.num.cachemiss if due to timeouts no replies were sent for some queries.
|
||||
.TP
|
||||
.I threadX.requestlist.avg
|
||||
The average number of requests in the internal recursive processing request list on insert of a new incoming recursive processing query.
|
||||
.TP
|
||||
.I threadX.requestlist.max
|
||||
Maximum size attained by the internal recursive processing request list.
|
||||
.TP
|
||||
.I threadX.requestlist.overwritten
|
||||
Number of requests in the request list that were overwritten by newer entries. This happens if there is a flood of queries that recursive processing and the server has a hard time.
|
||||
.TP
|
||||
.I threadX.requestlist.exceeded
|
||||
Queries that were dropped because the request list was full. This happens if a flood of queries need recursive processing, and the server can not keep up.
|
||||
.TP
|
||||
.I threadX.requestlist.current.all
|
||||
Current size of the request list, includes internally generated queries (such
|
||||
as priming queries and glue lookups).
|
||||
.TP
|
||||
.I threadX.requestlist.current.user
|
||||
Current size of the request list, only the requests from client queries.
|
||||
.TP
|
||||
.I threadX.recursion.time.avg
|
||||
Average time it took to answer queries that needed recursive processing. Note that queries that were answered from the cache are not in this average.
|
||||
.TP
|
||||
.I threadX.recursion.time.median
|
||||
The median of the time it took to answer queries that needed recursive
|
||||
processing. The median means that 50% of the user queries were answered in
|
||||
less than this time. Because of big outliers (usually queries to non
|
||||
responsive servers), the average can be bigger than the median. This median
|
||||
has been calculated by interpolation from a histogram.
|
||||
.TP
|
||||
.I total.num.queries
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.cachehits
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.cachemiss
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.prefetch
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.recursivereplies
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.requestlist.avg
|
||||
averaged over threads.
|
||||
.TP
|
||||
.I total.requestlist.max
|
||||
the maximum of the thread requestlist.max values.
|
||||
.TP
|
||||
.I total.requestlist.overwritten
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.requestlist.exceeded
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.requestlist.current.all
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.recursion.time.median
|
||||
averaged over threads.
|
||||
.TP
|
||||
.I time.now
|
||||
current time in seconds since 1970.
|
||||
.TP
|
||||
.I time.up
|
||||
uptime since server boot in seconds.
|
||||
.TP
|
||||
.I time.elapsed
|
||||
time since last statistics printout, in seconds.
|
||||
.SH EXTENDED STATISTICS
|
||||
.TP
|
||||
.I mem.total.sbrk
|
||||
If sbrk(2) is available, an estimate of the heap size of the program in number of bytes. Close to the total memory used by the program, as reported by top and ps. Could be wrong if the OS allocates memory non\-contiguously.
|
||||
.TP
|
||||
.I mem.cache.rrset
|
||||
Memory in bytes in use by the RRset cache.
|
||||
.TP
|
||||
.I mem.cache.message
|
||||
Memory in bytes in use by the message cache.
|
||||
.TP
|
||||
.I mem.mod.iterator
|
||||
Memory in bytes in use by the iterator module.
|
||||
.TP
|
||||
.I mem.mod.validator
|
||||
Memory in bytes in use by the validator module. Includes the key cache and
|
||||
negative cache.
|
||||
.TP
|
||||
.I histogram.<sec>.<usec>.to.<sec>.<usec>
|
||||
Shows a histogram, summed over all threads. Every element counts the
|
||||
recursive queries whose reply time fit between the lower and upper bound.
|
||||
Times larger or equal to the lowerbound, and smaller than the upper bound.
|
||||
There are 40 buckets, with bucket sizes doubling.
|
||||
.TP
|
||||
.I num.query.type.A
|
||||
The total number of queries over all threads with query type A.
|
||||
Printed for the other query types as well, but only for the types for which
|
||||
queries were received, thus =0 entries are omitted for brevity.
|
||||
.TP
|
||||
.I num.query.type.other
|
||||
Number of queries with query types 256\-65535.
|
||||
.TP
|
||||
.I num.query.class.IN
|
||||
The total number of queries over all threads with query class IN (internet).
|
||||
Also printed for other classes (such as CH (CHAOS) sometimes used for
|
||||
debugging), or NONE, ANY, used by dynamic update.
|
||||
num.query.class.other is printed for classes 256\-65535.
|
||||
.TP
|
||||
.I num.query.opcode.QUERY
|
||||
The total number of queries over all threads with query opcode QUERY.
|
||||
Also printed for other opcodes, UPDATE, ...
|
||||
.TP
|
||||
.I num.query.tcp
|
||||
Number of queries that were made using TCP towards the unbound server.
|
||||
.TP
|
||||
.I num.query.ipv6
|
||||
Number of queries that were made using IPv6 towards the unbound server.
|
||||
.TP
|
||||
.I num.query.flags.RD
|
||||
The number of queries that had the RD flag set in the header.
|
||||
Also printed for flags QR, AA, TC, RA, Z, AD, CD.
|
||||
Note that queries with flags QR, AA or TC may have been rejected
|
||||
because of that.
|
||||
.TP
|
||||
.I num.query.edns.present
|
||||
number of queries that had an EDNS OPT record present.
|
||||
.TP
|
||||
.I num.query.edns.DO
|
||||
number of queries that had an EDNS OPT record with the DO (DNSSEC OK) bit set.
|
||||
These queries are also included in the num.query.edns.present number.
|
||||
.TP
|
||||
.I num.answer.rcode.NXDOMAIN
|
||||
The number of answers to queries, from cache or from recursion, that had the
|
||||
return code NXDOMAIN. Also printed for the other return codes.
|
||||
.TP
|
||||
.I num.answer.rcode.nodata
|
||||
The number of answers to queries that had the pseudo return code nodata.
|
||||
This means the actual return code was NOERROR, but additionally, no data was
|
||||
carried in the answer (making what is called a NOERROR/NODATA answer).
|
||||
These queries are also included in the num.answer.rcode.NOERROR number.
|
||||
Common for AAAA lookups when an A record exists, and no AAAA.
|
||||
.TP
|
||||
.I num.answer.secure
|
||||
Number of answers that were secure. The answer validated correctly.
|
||||
The AD bit might have been set in some of these answers, where the client
|
||||
signalled (with DO or AD bit in the query) that they were ready to accept
|
||||
the AD bit in the answer.
|
||||
.TP
|
||||
.I num.answer.bogus
|
||||
Number of answers that were bogus. These answers resulted in SERVFAIL
|
||||
to the client because the answer failed validation.
|
||||
.TP
|
||||
.I num.rrset.bogus
|
||||
The number of rrsets marked bogus by the validator. Increased for every
|
||||
RRset inspection that fails.
|
||||
.TP
|
||||
.I unwanted.queries
|
||||
Number of queries that were refused or dropped because they failed the
|
||||
access control settings.
|
||||
.TP
|
||||
.I unwanted.replies
|
||||
Replies that were unwanted or unsolicited. Could have been random traffic,
|
||||
delayed duplicates, very late answers, or could be spoofing attempts.
|
||||
Some low level of late answers and delayed duplicates are to be expected
|
||||
with the UDP protocol. Very high values could indicate a threat (spoofing).
|
||||
.SH "FILES"
|
||||
.TP
|
||||
.I @ub_conf_file@
|
||||
unbound configuration file.
|
||||
.TP
|
||||
.I @UNBOUND_RUN_DIR@
|
||||
directory with private keys (unbound_server.key and unbound_control.key) and
|
||||
self\-signed certificates (unbound_server.pem and unbound_control.pem).
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
116
contrib/unbound/doc/unbound-host.1
Normal file
116
contrib/unbound/doc/unbound-host.1
Normal file
@ -0,0 +1,116 @@
|
||||
.TH "unbound\-host" "1" "May 24, 2012" "NLnet Labs" "unbound 1.4.17"
|
||||
.\"
|
||||
.\" unbound-host.1 -- unbound DNS lookup utility
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.LP
|
||||
.B unbound\-host
|
||||
\- unbound DNS lookup utility
|
||||
.SH "SYNOPSIS"
|
||||
.LP
|
||||
.B unbound\-host
|
||||
.RB [ \-vdhr46 ]
|
||||
.RB [ \-c
|
||||
.IR class ]
|
||||
.RB [ \-t
|
||||
.IR type ]
|
||||
.I hostname
|
||||
.RB [ \-y
|
||||
.IR key ]
|
||||
.RB [ \-f
|
||||
.IR keyfile ]
|
||||
.RB [ \-F
|
||||
.IR namedkeyfile ]
|
||||
.RB [ \-C
|
||||
.IR configfile ]
|
||||
.SH "DESCRIPTION"
|
||||
.LP
|
||||
.B Unbound\-host
|
||||
uses the unbound validating resolver to query for the hostname and display
|
||||
results. With the \fB\-v\fR option it displays validation
|
||||
status: secure, insecure, bogus (security failure).
|
||||
.P
|
||||
By default it reads no configuration file whatsoever. It attempts to reach
|
||||
the internet root servers. With \fB\-C\fR an unbound config file and with
|
||||
\fB\-r\fR resolv.conf can be read.
|
||||
.P
|
||||
The available options are:
|
||||
.TP
|
||||
.I hostname
|
||||
This name is resolved (looked up in the DNS).
|
||||
If a IPv4 or IPv6 address is given, a reverse lookup is performed.
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.TP
|
||||
.B \-v
|
||||
Enable verbose output and it shows validation results, on every line.
|
||||
Secure means that the NXDOMAIN (no such domain name), nodata (no such data)
|
||||
or positive data response validated correctly with one of the keys.
|
||||
Insecure means that that domain name has no security set up for it.
|
||||
Bogus (security failure) means that the response failed one or more checks,
|
||||
it is likely wrong, outdated, tampered with, or broken.
|
||||
.TP
|
||||
.B \-d
|
||||
Enable debug output to stderr. One \-d shows what the resolver and validator
|
||||
are doing and may tell you what is going on. More times, \-d \-d, gives a
|
||||
lot of output, with every packet sent and received.
|
||||
.TP
|
||||
.B \-c \fIclass
|
||||
Specify the class to lookup for, the default is IN the internet class.
|
||||
.TP
|
||||
.B \-t \fItype
|
||||
Specify the type of data to lookup. The default looks for IPv4, IPv6 and
|
||||
mail handler data, or domain name pointers for reverse queries.
|
||||
.TP
|
||||
.B \-y \fIkey
|
||||
Specify a public key to use as trust anchor. This is the base for a chain
|
||||
of trust that is built up from the trust anchor to the response, in order
|
||||
to validate the response message. Can be given as a DS or DNSKEY record.
|
||||
For example \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD".
|
||||
.TP
|
||||
.B \-f \fIkeyfile
|
||||
Reads keys from a file. Every line has a DS or DNSKEY record, in the format
|
||||
as for \-y. The zone file format, the same as dig and drill produce.
|
||||
.TP
|
||||
.B \-F \fInamedkeyfile
|
||||
Reads keys from a BIND\-style named.conf file. Only the trusted\-key {}; entries
|
||||
are read.
|
||||
.TP
|
||||
.B \-C \fIconfigfile
|
||||
Uses the specified unbound.conf to prime
|
||||
.IR libunbound (3).
|
||||
.TP
|
||||
.B \-r
|
||||
Read /etc/resolv.conf, and use the forward DNS servers from there (those could
|
||||
have been set by DHCP). More info in
|
||||
.IR resolv.conf (5).
|
||||
Breaks validation if those servers do not support DNSSEC.
|
||||
.TP
|
||||
.B \-4
|
||||
Use solely the IPv4 network for sending packets.
|
||||
.TP
|
||||
.B \-6
|
||||
Use solely the IPv6 network for sending packets.
|
||||
.SH "EXAMPLES"
|
||||
.LP
|
||||
Some examples of use. The keys shown below are fakes, thus a security failure
|
||||
is encountered.
|
||||
.P
|
||||
$ unbound\-host www.example.com
|
||||
.P
|
||||
$ unbound\-host \-v \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD" www.example.com
|
||||
.P
|
||||
$ unbound\-host \-v \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD" 192.0.2.153
|
||||
.SH "EXIT CODE"
|
||||
The unbound\-host program exits with status code 1 on error,
|
||||
0 on no error. The data may not be available on exit code 0, exit code 1
|
||||
means the lookup encountered a fatal error.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
51
contrib/unbound/doc/unbound.8.in
Normal file
51
contrib/unbound/doc/unbound.8.in
Normal file
@ -0,0 +1,51 @@
|
||||
.TH "unbound" "8" "May 24, 2012" "NLnet Labs" "unbound 1.4.17"
|
||||
.\"
|
||||
.\" unbound.8 -- unbound manual
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.LP
|
||||
.B unbound
|
||||
\- Unbound DNS validating resolver 1.4.17.
|
||||
.SH "SYNOPSIS"
|
||||
.LP
|
||||
.B unbound
|
||||
.RB [ \-h ]
|
||||
.RB [ \-d ]
|
||||
.RB [ \-v ]
|
||||
.RB [ \-c
|
||||
.IR cfgfile ]
|
||||
.SH "DESCRIPTION"
|
||||
.LP
|
||||
.B Unbound
|
||||
is an implementation of a DNS resolver, that does caching and
|
||||
DNSSEC validation.
|
||||
.P
|
||||
The available options are:
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.TP
|
||||
.B \-c\fI cfgfile
|
||||
Set the config file with settings for unbound to read instead of reading the
|
||||
file at the default location, @ub_conf_file@. The syntax is
|
||||
described in \fIunbound.conf\fR(5).
|
||||
.TP
|
||||
.B \-d
|
||||
Debug flag, do not fork into the background, but stay attached to the
|
||||
console. This flag will also delay writing to the logfile until the
|
||||
thread\-spawn time. So that most config and setup errors appear on stderr.
|
||||
.TP
|
||||
.B \-v
|
||||
Increase verbosity. If given multiple times, more information is logged.
|
||||
This is in addition to the verbosity (if any) from the config file.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\-checkconf\fR(8).
|
||||
.SH "AUTHORS"
|
||||
.B Unbound
|
||||
developers are mentioned in the CREDITS file in the distribution.
|
1094
contrib/unbound/doc/unbound.conf.5.in
Normal file
1094
contrib/unbound/doc/unbound.conf.5.in
Normal file
File diff suppressed because it is too large
Load Diff
1648
contrib/unbound/doc/unbound.doxygen
Normal file
1648
contrib/unbound/doc/unbound.doxygen
Normal file
File diff suppressed because it is too large
Load Diff
520
contrib/unbound/install-sh
Executable file
520
contrib/unbound/install-sh
Executable file
@ -0,0 +1,520 @@
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# 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
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
nl='
|
||||
'
|
||||
IFS=" "" $nl"
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit=${DOITPROG-}
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_glob='?'
|
||||
initialize_posix_glob='
|
||||
test "$posix_glob" != "?" || {
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=
|
||||
else
|
||||
posix_glob=:
|
||||
fi
|
||||
}
|
||||
'
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
no_target_directory=
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call `install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
trap '(exit $?); exit' 1 2 13 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names starting with `-'.
|
||||
case $src in
|
||||
-*) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dst=$dst_arg
|
||||
# Protect names starting with `-'.
|
||||
case $dst in
|
||||
-*) dst=./$dst;;
|
||||
esac
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
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.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
-*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
eval "$initialize_posix_glob"
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
$posix_glob set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
$posix_glob set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test -z "$d" && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
|
||||
eval "$initialize_posix_glob" &&
|
||||
$posix_glob set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
$posix_glob set +f &&
|
||||
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
640
contrib/unbound/iterator/iter_delegpt.c
Normal file
640
contrib/unbound/iterator/iter_delegpt.c
Normal file
@ -0,0 +1,640 @@
|
||||
/*
|
||||
* iterator/iter_delegpt.c - delegation point with NS and address information.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file implements the Delegation Point. It contains a list of name servers
|
||||
* and their addresses if known.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "iterator/iter_delegpt.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/data/packed_rrset.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/net_help.h"
|
||||
|
||||
struct delegpt*
|
||||
delegpt_create(struct regional* region)
|
||||
{
|
||||
struct delegpt* dp=(struct delegpt*)regional_alloc(
|
||||
region, sizeof(*dp));
|
||||
if(!dp)
|
||||
return NULL;
|
||||
memset(dp, 0, sizeof(*dp));
|
||||
return dp;
|
||||
}
|
||||
|
||||
struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
|
||||
{
|
||||
struct delegpt* copy = delegpt_create(region);
|
||||
struct delegpt_ns* ns;
|
||||
struct delegpt_addr* a;
|
||||
if(!copy)
|
||||
return NULL;
|
||||
if(!delegpt_set_name(copy, region, dp->name))
|
||||
return NULL;
|
||||
copy->bogus = dp->bogus;
|
||||
copy->has_parent_side_NS = dp->has_parent_side_NS;
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
if(!delegpt_add_ns(copy, region, ns->name, (int)ns->lame))
|
||||
return NULL;
|
||||
copy->nslist->resolved = ns->resolved;
|
||||
copy->nslist->got4 = ns->got4;
|
||||
copy->nslist->got6 = ns->got6;
|
||||
copy->nslist->done_pside4 = ns->done_pside4;
|
||||
copy->nslist->done_pside6 = ns->done_pside6;
|
||||
}
|
||||
for(a = dp->target_list; a; a = a->next_target) {
|
||||
if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen,
|
||||
a->bogus, a->lame))
|
||||
return NULL;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name)
|
||||
{
|
||||
log_assert(!dp->dp_type_mlc);
|
||||
dp->namelabs = dname_count_size_labels(name, &dp->namelen);
|
||||
dp->name = regional_alloc_init(region, name, dp->namelen);
|
||||
return dp->name != 0;
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
|
||||
int lame)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
size_t len;
|
||||
(void)dname_count_size_labels(name, &len);
|
||||
log_assert(!dp->dp_type_mlc);
|
||||
/* slow check for duplicates to avoid counting failures when
|
||||
* adding the same server as a dependency twice */
|
||||
if(delegpt_find_ns(dp, name, len))
|
||||
return 1;
|
||||
ns = (struct delegpt_ns*)regional_alloc(region,
|
||||
sizeof(struct delegpt_ns));
|
||||
if(!ns)
|
||||
return 0;
|
||||
ns->next = dp->nslist;
|
||||
ns->namelen = len;
|
||||
dp->nslist = ns;
|
||||
ns->name = regional_alloc_init(region, name, ns->namelen);
|
||||
ns->resolved = 0;
|
||||
ns->got4 = 0;
|
||||
ns->got6 = 0;
|
||||
ns->lame = (uint8_t)lame;
|
||||
ns->done_pside4 = 0;
|
||||
ns->done_pside6 = 0;
|
||||
return ns->name != 0;
|
||||
}
|
||||
|
||||
struct delegpt_ns*
|
||||
delegpt_find_ns(struct delegpt* dp, uint8_t* name, size_t namelen)
|
||||
{
|
||||
struct delegpt_ns* p = dp->nslist;
|
||||
while(p) {
|
||||
if(namelen == p->namelen &&
|
||||
query_dname_compare(name, p->name) == 0) {
|
||||
return p;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct delegpt_addr*
|
||||
delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
struct delegpt_addr* p = dp->target_list;
|
||||
while(p) {
|
||||
if(sockaddr_cmp_addr(addr, addrlen, &p->addr, p->addrlen)==0) {
|
||||
return p;
|
||||
}
|
||||
p = p->next_target;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_target(struct delegpt* dp, struct regional* region,
|
||||
uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int bogus, int lame)
|
||||
{
|
||||
struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen);
|
||||
log_assert(!dp->dp_type_mlc);
|
||||
if(!ns) {
|
||||
/* ignore it */
|
||||
return 1;
|
||||
}
|
||||
if(!lame) {
|
||||
if(addr_is_ip6(addr, addrlen))
|
||||
ns->got6 = 1;
|
||||
else ns->got4 = 1;
|
||||
if(ns->got4 && ns->got6)
|
||||
ns->resolved = 1;
|
||||
}
|
||||
return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame);
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_addr(struct delegpt* dp, struct regional* region,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int bogus,
|
||||
int lame)
|
||||
{
|
||||
struct delegpt_addr* a;
|
||||
log_assert(!dp->dp_type_mlc);
|
||||
/* check for duplicates */
|
||||
if((a = delegpt_find_addr(dp, addr, addrlen))) {
|
||||
if(bogus)
|
||||
a->bogus = bogus;
|
||||
if(!lame)
|
||||
a->lame = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
a = (struct delegpt_addr*)regional_alloc(region,
|
||||
sizeof(struct delegpt_addr));
|
||||
if(!a)
|
||||
return 0;
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_result = 0;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
memcpy(&a->addr, addr, addrlen);
|
||||
a->addrlen = addrlen;
|
||||
a->attempts = 0;
|
||||
a->bogus = bogus;
|
||||
a->lame = lame;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
*numns = 0;
|
||||
*missing = 0;
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
(*numns)++;
|
||||
if(!ns->resolved)
|
||||
(*missing)++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres,
|
||||
size_t* numavail)
|
||||
{
|
||||
struct delegpt_addr* a;
|
||||
*numaddr = 0;
|
||||
*numres = 0;
|
||||
*numavail = 0;
|
||||
for(a = dp->target_list; a; a = a->next_target) {
|
||||
(*numaddr)++;
|
||||
}
|
||||
for(a = dp->result_list; a; a = a->next_result) {
|
||||
(*numres)++;
|
||||
}
|
||||
for(a = dp->usable_list; a; a = a->next_usable) {
|
||||
(*numavail)++;
|
||||
}
|
||||
}
|
||||
|
||||
void delegpt_log(enum verbosity_value v, struct delegpt* dp)
|
||||
{
|
||||
char buf[LDNS_MAX_DOMAINLEN+1];
|
||||
struct delegpt_ns* ns;
|
||||
struct delegpt_addr* a;
|
||||
size_t missing=0, numns=0, numaddr=0, numres=0, numavail=0;
|
||||
if(verbosity < v)
|
||||
return;
|
||||
dname_str(dp->name, buf);
|
||||
if(dp->nslist == NULL && dp->target_list == NULL) {
|
||||
log_info("DelegationPoint<%s>: empty", buf);
|
||||
return;
|
||||
}
|
||||
delegpt_count_ns(dp, &numns, &missing);
|
||||
delegpt_count_addr(dp, &numaddr, &numres, &numavail);
|
||||
log_info("DelegationPoint<%s>: %u names (%u missing), "
|
||||
"%u addrs (%u result, %u avail)%s",
|
||||
buf, (unsigned)numns, (unsigned)missing,
|
||||
(unsigned)numaddr, (unsigned)numres, (unsigned)numavail,
|
||||
(dp->has_parent_side_NS?" parentNS":" cacheNS"));
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
dname_str(ns->name, buf);
|
||||
log_info(" %s %s%s%s%s%s%s%s", buf,
|
||||
(ns->resolved?"*":""),
|
||||
(ns->got4?" A":""), (ns->got6?" AAAA":""),
|
||||
(dp->bogus?" BOGUS":""), (ns->lame?" PARENTSIDE":""),
|
||||
(ns->done_pside4?" PSIDE_A":""),
|
||||
(ns->done_pside6?" PSIDE_AAAA":""));
|
||||
}
|
||||
for(a = dp->target_list; a; a = a->next_target) {
|
||||
const char* str = " ";
|
||||
if(a->bogus && a->lame) str = " BOGUS ADDR_LAME ";
|
||||
else if(a->bogus) str = " BOGUS ";
|
||||
else if(a->lame) str = " ADDR_LAME ";
|
||||
log_addr(VERB_ALGO, str, &a->addr, a->addrlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
delegpt_add_unused_targets(struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_addr* usa = dp->usable_list;
|
||||
dp->usable_list = NULL;
|
||||
while(usa) {
|
||||
usa->next_result = dp->result_list;
|
||||
dp->result_list = usa;
|
||||
usa = usa->next_usable;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
delegpt_count_targets(struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_addr* a;
|
||||
size_t n = 0;
|
||||
for(a = dp->target_list; a; a = a->next_target)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t
|
||||
delegpt_count_missing_targets(struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
size_t n = 0;
|
||||
for(ns = dp->nslist; ns; ns = ns->next)
|
||||
if(!ns->resolved)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
/** find NS rrset in given list */
|
||||
static struct ub_packed_rrset_key*
|
||||
find_NS(struct reply_info* rep, size_t from, size_t to)
|
||||
{
|
||||
size_t i;
|
||||
for(i=from; i<to; i++) {
|
||||
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
|
||||
return rep->rrsets[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
{
|
||||
struct ub_packed_rrset_key* ns_rrset = NULL;
|
||||
struct delegpt* dp;
|
||||
size_t i;
|
||||
/* look for NS records in the authority section... */
|
||||
ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets,
|
||||
msg->rep->an_numrrsets+msg->rep->ns_numrrsets);
|
||||
|
||||
/* In some cases (even legitimate, perfectly legal cases), the
|
||||
* NS set for the "referral" might be in the answer section. */
|
||||
if(!ns_rrset)
|
||||
ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets);
|
||||
|
||||
/* If there was no NS rrset in the authority section, then this
|
||||
* wasn't a referral message. (It might not actually be a
|
||||
* referral message anyway) */
|
||||
if(!ns_rrset)
|
||||
return NULL;
|
||||
|
||||
/* If we found any, then Yay! we have a delegation point. */
|
||||
dp = delegpt_create(region);
|
||||
if(!dp)
|
||||
return NULL;
|
||||
dp->has_parent_side_NS = 1; /* created from message */
|
||||
if(!delegpt_set_name(dp, region, ns_rrset->rk.dname))
|
||||
return NULL;
|
||||
if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0))
|
||||
return NULL;
|
||||
|
||||
/* add glue, A and AAAA in answer and additional section */
|
||||
for(i=0; i<msg->rep->rrset_count; i++) {
|
||||
struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
|
||||
/* skip auth section. FIXME really needed?*/
|
||||
if(msg->rep->an_numrrsets <= i &&
|
||||
i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets))
|
||||
continue;
|
||||
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) {
|
||||
if(!delegpt_add_rrset_A(dp, region, s, 0))
|
||||
return NULL;
|
||||
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) {
|
||||
if(!delegpt_add_rrset_AAAA(dp, region, s, 0))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* ns_rrset, int lame)
|
||||
{
|
||||
struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
|
||||
ns_rrset->entry.data;
|
||||
size_t i;
|
||||
log_assert(!dp->dp_type_mlc);
|
||||
if(nsdata->security == sec_status_bogus)
|
||||
dp->bogus = 1;
|
||||
for(i=0; i<nsdata->count; i++) {
|
||||
if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */
|
||||
if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) !=
|
||||
(size_t)ldns_read_uint16(nsdata->rr_data[i]))
|
||||
continue; /* bad format */
|
||||
/* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
|
||||
if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_rrset_A(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* ak, int lame)
|
||||
{
|
||||
struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
|
||||
size_t i;
|
||||
struct sockaddr_in sa;
|
||||
socklen_t len = (socklen_t)sizeof(sa);
|
||||
log_assert(!dp->dp_type_mlc);
|
||||
memset(&sa, 0, len);
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
for(i=0; i<d->count; i++) {
|
||||
if(d->rr_len[i] != 2 + INET_SIZE)
|
||||
continue;
|
||||
memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE);
|
||||
if(!delegpt_add_target(dp, region, ak->rk.dname,
|
||||
ak->rk.dname_len, (struct sockaddr_storage*)&sa,
|
||||
len, (d->security==sec_status_bogus), lame))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* ak, int lame)
|
||||
{
|
||||
struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
|
||||
size_t i;
|
||||
struct sockaddr_in6 sa;
|
||||
socklen_t len = (socklen_t)sizeof(sa);
|
||||
log_assert(!dp->dp_type_mlc);
|
||||
memset(&sa, 0, len);
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
for(i=0; i<d->count; i++) {
|
||||
if(d->rr_len[i] != 2 + INET6_SIZE) /* rdatalen + len of IP6 */
|
||||
continue;
|
||||
memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE);
|
||||
if(!delegpt_add_target(dp, region, ak->rk.dname,
|
||||
ak->rk.dname_len, (struct sockaddr_storage*)&sa,
|
||||
len, (d->security==sec_status_bogus), lame))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_rrset(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* rrset, int lame)
|
||||
{
|
||||
if(!rrset)
|
||||
return 1;
|
||||
if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS)
|
||||
return delegpt_rrset_add_ns(dp, region, rrset, lame);
|
||||
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A)
|
||||
return delegpt_add_rrset_A(dp, region, rrset, lame);
|
||||
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA)
|
||||
return delegpt_add_rrset_AAAA(dp, region, rrset, lame);
|
||||
log_warn("Unknown rrset type added to delegpt");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg)
|
||||
{
|
||||
struct reply_info* rep = (struct reply_info*)msg->entry.data;
|
||||
if(!rep) return;
|
||||
|
||||
/* if error or no answers */
|
||||
if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) {
|
||||
struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname,
|
||||
msg->key.qname_len);
|
||||
if(ns) {
|
||||
if(msg->key.qtype == LDNS_RR_TYPE_A)
|
||||
ns->got4 = 1;
|
||||
else if(msg->key.qtype == LDNS_RR_TYPE_AAAA)
|
||||
ns->got6 = 1;
|
||||
if(ns->got4 && ns->got6)
|
||||
ns->resolved = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void delegpt_no_ipv6(struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
/* no ipv6, so only ipv4 is enough to resolve a nameserver */
|
||||
if(ns->got4)
|
||||
ns->resolved = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void delegpt_no_ipv4(struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
/* no ipv4, so only ipv6 is enough to resolve a nameserver */
|
||||
if(ns->got6)
|
||||
ns->resolved = 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct delegpt* delegpt_create_mlc(uint8_t* name)
|
||||
{
|
||||
struct delegpt* dp=(struct delegpt*)calloc(1, sizeof(*dp));
|
||||
if(!dp)
|
||||
return NULL;
|
||||
dp->dp_type_mlc = 1;
|
||||
if(name) {
|
||||
dp->namelabs = dname_count_size_labels(name, &dp->namelen);
|
||||
dp->name = memdup(name, dp->namelen);
|
||||
if(!dp->name) {
|
||||
free(dp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
void delegpt_free_mlc(struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_ns* n, *nn;
|
||||
struct delegpt_addr* a, *na;
|
||||
if(!dp) return;
|
||||
log_assert(dp->dp_type_mlc);
|
||||
n = dp->nslist;
|
||||
while(n) {
|
||||
nn = n->next;
|
||||
free(n->name);
|
||||
free(n);
|
||||
n = nn;
|
||||
}
|
||||
a = dp->target_list;
|
||||
while(a) {
|
||||
na = a->next_target;
|
||||
free(a);
|
||||
a = na;
|
||||
}
|
||||
free(dp->name);
|
||||
free(dp);
|
||||
}
|
||||
|
||||
int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name)
|
||||
{
|
||||
log_assert(dp->dp_type_mlc);
|
||||
dp->namelabs = dname_count_size_labels(name, &dp->namelen);
|
||||
dp->name = memdup(name, dp->namelen);
|
||||
return (dp->name != NULL);
|
||||
}
|
||||
|
||||
int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, int lame)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
size_t len;
|
||||
(void)dname_count_size_labels(name, &len);
|
||||
log_assert(dp->dp_type_mlc);
|
||||
/* slow check for duplicates to avoid counting failures when
|
||||
* adding the same server as a dependency twice */
|
||||
if(delegpt_find_ns(dp, name, len))
|
||||
return 1;
|
||||
ns = (struct delegpt_ns*)malloc(sizeof(struct delegpt_ns));
|
||||
if(!ns)
|
||||
return 0;
|
||||
ns->namelen = len;
|
||||
ns->name = memdup(name, ns->namelen);
|
||||
if(!ns->name) {
|
||||
free(ns);
|
||||
return 0;
|
||||
}
|
||||
ns->next = dp->nslist;
|
||||
dp->nslist = ns;
|
||||
ns->resolved = 0;
|
||||
ns->got4 = 0;
|
||||
ns->got6 = 0;
|
||||
ns->lame = (uint8_t)lame;
|
||||
ns->done_pside4 = 0;
|
||||
ns->done_pside6 = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int bogus, int lame)
|
||||
{
|
||||
struct delegpt_addr* a;
|
||||
log_assert(dp->dp_type_mlc);
|
||||
/* check for duplicates */
|
||||
if((a = delegpt_find_addr(dp, addr, addrlen))) {
|
||||
if(bogus)
|
||||
a->bogus = bogus;
|
||||
if(!lame)
|
||||
a->lame = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr));
|
||||
if(!a)
|
||||
return 0;
|
||||
a->next_target = dp->target_list;
|
||||
dp->target_list = a;
|
||||
a->next_result = 0;
|
||||
a->next_usable = dp->usable_list;
|
||||
dp->usable_list = a;
|
||||
memcpy(&a->addr, addr, addrlen);
|
||||
a->addrlen = addrlen;
|
||||
a->attempts = 0;
|
||||
a->bogus = bogus;
|
||||
a->lame = lame;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int bogus, int lame)
|
||||
{
|
||||
struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen);
|
||||
log_assert(dp->dp_type_mlc);
|
||||
if(!ns) {
|
||||
/* ignore it */
|
||||
return 1;
|
||||
}
|
||||
if(!lame) {
|
||||
if(addr_is_ip6(addr, addrlen))
|
||||
ns->got6 = 1;
|
||||
else ns->got4 = 1;
|
||||
if(ns->got4 && ns->got6)
|
||||
ns->resolved = 1;
|
||||
}
|
||||
return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame);
|
||||
}
|
||||
|
||||
size_t delegpt_get_mem(struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
size_t s;
|
||||
if(!dp) return 0;
|
||||
s = sizeof(*dp) + dp->namelen +
|
||||
delegpt_count_targets(dp)*sizeof(struct delegpt_addr);
|
||||
for(ns=dp->nslist; ns; ns=ns->next)
|
||||
s += sizeof(*ns)+ns->namelen;
|
||||
return s;
|
||||
}
|
411
contrib/unbound/iterator/iter_delegpt.h
Normal file
411
contrib/unbound/iterator/iter_delegpt.h
Normal file
@ -0,0 +1,411 @@
|
||||
/*
|
||||
* iterator/iter_delegpt.h - delegation point with NS and address information.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file implements the Delegation Point. It contains a list of name servers
|
||||
* and their addresses if known.
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_ITER_DELEGPT_H
|
||||
#define ITERATOR_ITER_DELEGPT_H
|
||||
#include "util/log.h"
|
||||
struct regional;
|
||||
struct delegpt_ns;
|
||||
struct delegpt_addr;
|
||||
struct dns_msg;
|
||||
struct ub_packed_rrset_key;
|
||||
struct msgreply_entry;
|
||||
|
||||
/**
|
||||
* Delegation Point.
|
||||
* For a domain name, the NS rrset, and the A and AAAA records for those.
|
||||
*/
|
||||
struct delegpt {
|
||||
/** the domain name of the delegation point. */
|
||||
uint8_t* name;
|
||||
/** length of the delegation point name */
|
||||
size_t namelen;
|
||||
/** number of labels in delegation point */
|
||||
int namelabs;
|
||||
|
||||
/** the nameservers, names from the NS RRset rdata. */
|
||||
struct delegpt_ns* nslist;
|
||||
/** the target addresses for delegation */
|
||||
struct delegpt_addr* target_list;
|
||||
/** the list of usable targets; subset of target_list
|
||||
* the items in this list are not part of the result list. */
|
||||
struct delegpt_addr* usable_list;
|
||||
/** the list of returned targets; subset of target_list */
|
||||
struct delegpt_addr* result_list;
|
||||
|
||||
/** if true, the NS RRset was bogus. All info is bad. */
|
||||
int bogus;
|
||||
/** if true, the parent-side NS record has been applied:
|
||||
* its names have been added and their addresses can follow later.
|
||||
* Also true if the delegationpoint was created from a delegation
|
||||
* message and thus contains the parent-side-info already. */
|
||||
uint8_t has_parent_side_NS;
|
||||
/** for assertions on type of delegpt */
|
||||
uint8_t dp_type_mlc;
|
||||
};
|
||||
|
||||
/**
|
||||
* Nameservers for a delegation point.
|
||||
*/
|
||||
struct delegpt_ns {
|
||||
/** next in list */
|
||||
struct delegpt_ns* next;
|
||||
/** name of nameserver */
|
||||
uint8_t* name;
|
||||
/** length of name */
|
||||
size_t namelen;
|
||||
/**
|
||||
* If the name has been resolved. false if not queried for yet.
|
||||
* true if the A, AAAA queries have been generated.
|
||||
* marked true if those queries fail.
|
||||
* and marked true if got4 and got6 are both true.
|
||||
*/
|
||||
int resolved;
|
||||
/** if the ipv4 address is in the delegpt */
|
||||
uint8_t got4;
|
||||
/** if the ipv6 address is in the delegpt */
|
||||
uint8_t got6;
|
||||
/**
|
||||
* If the name is parent-side only and thus dispreferred.
|
||||
* Its addresses become dispreferred as well
|
||||
*/
|
||||
uint8_t lame;
|
||||
/** if the parent-side ipv4 address has been looked up (last resort).
|
||||
* Also enabled if a parent-side cache entry exists, or a parent-side
|
||||
* negative-cache entry exists. */
|
||||
uint8_t done_pside4;
|
||||
/** if the parent-side ipv6 address has been looked up (last resort).
|
||||
* Also enabled if a parent-side cache entry exists, or a parent-side
|
||||
* negative-cache entry exists. */
|
||||
uint8_t done_pside6;
|
||||
};
|
||||
|
||||
/**
|
||||
* Address of target nameserver in delegation point.
|
||||
*/
|
||||
struct delegpt_addr {
|
||||
/** next delegation point in results */
|
||||
struct delegpt_addr* next_result;
|
||||
/** next delegation point in usable list */
|
||||
struct delegpt_addr* next_usable;
|
||||
/** next delegation point in all targets list */
|
||||
struct delegpt_addr* next_target;
|
||||
|
||||
/** delegation point address */
|
||||
struct sockaddr_storage addr;
|
||||
/** length of addr */
|
||||
socklen_t addrlen;
|
||||
/** number of attempts for this addr */
|
||||
int attempts;
|
||||
/** rtt stored here in the selection algorithm */
|
||||
int sel_rtt;
|
||||
/** if true, the A or AAAA RR was bogus, so this address is bad.
|
||||
* Also check the dp->bogus to see if everything is bogus. */
|
||||
int bogus;
|
||||
/** if true, this address is dispreferred: it is a lame IP address */
|
||||
int lame;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create new delegation point.
|
||||
* @param regional: where to allocate it.
|
||||
* @return new delegation point or NULL on error.
|
||||
*/
|
||||
struct delegpt* delegpt_create(struct regional* regional);
|
||||
|
||||
/**
|
||||
* Create a copy of a delegation point.
|
||||
* @param dp: delegation point to copy.
|
||||
* @param regional: where to allocate it.
|
||||
* @return new delegation point or NULL on error.
|
||||
*/
|
||||
struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* regional);
|
||||
|
||||
/**
|
||||
* Set name of delegation point.
|
||||
* @param dp: delegation point.
|
||||
* @param regional: where to allocate the name copy.
|
||||
* @param name: name to use.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_set_name(struct delegpt* dp, struct regional* regional,
|
||||
uint8_t* name);
|
||||
|
||||
/**
|
||||
* Add a name to the delegation point.
|
||||
* @param dp: delegation point.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param name: domain name in wire format.
|
||||
* @param lame: name is lame, disprefer it.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_add_ns(struct delegpt* dp, struct regional* regional,
|
||||
uint8_t* name, int lame);
|
||||
|
||||
/**
|
||||
* Add NS rrset; calls add_ns repeatedly.
|
||||
* @param dp: delegation point.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param ns_rrset: NS rrset.
|
||||
* @param lame: rrset is lame, disprefer it.
|
||||
* @return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* ns_rrset, int lame);
|
||||
|
||||
/**
|
||||
* Add target address to the delegation point.
|
||||
* @param dp: delegation point.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param name: name for which target was found (must be in nslist).
|
||||
* This name is marked resolved.
|
||||
* @param namelen: length of name.
|
||||
* @param addr: the address.
|
||||
* @param addrlen: the length of addr.
|
||||
* @param bogus: security status for the address, pass true if bogus.
|
||||
* @param lame: address is lame.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_add_target(struct delegpt* dp, struct regional* regional,
|
||||
uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int bogus, int lame);
|
||||
|
||||
/**
|
||||
* Add A RRset to delegpt.
|
||||
* @param dp: delegation point.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param rrset: RRset A to add.
|
||||
* @param lame: rrset is lame, disprefer it.
|
||||
* @return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* rrset, int lame);
|
||||
|
||||
/**
|
||||
* Add AAAA RRset to delegpt.
|
||||
* @param dp: delegation point.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param rrset: RRset AAAA to add.
|
||||
* @param lame: rrset is lame, disprefer it.
|
||||
* @return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* rrset, int lame);
|
||||
|
||||
/**
|
||||
* Add any RRset to delegpt.
|
||||
* Does not check for duplicates added.
|
||||
* @param dp: delegation point.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param rrset: RRset to add, NS, A, AAAA.
|
||||
* @param lame: rrset is lame, disprefer it.
|
||||
* @return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_add_rrset(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* rrset, int lame);
|
||||
|
||||
/**
|
||||
* Add address to the delegation point. No servername is associated or checked.
|
||||
* @param dp: delegation point.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param addr: the address.
|
||||
* @param addrlen: the length of addr.
|
||||
* @param bogus: if address is bogus.
|
||||
* @param lame: if address is lame.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_add_addr(struct delegpt* dp, struct regional* regional,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int bogus, int lame);
|
||||
|
||||
/**
|
||||
* Find NS record in name list of delegation point.
|
||||
* @param dp: delegation point.
|
||||
* @param name: name of nameserver to look for, uncompressed wireformat.
|
||||
* @param namelen: length of name.
|
||||
* @return the ns structure or NULL if not found.
|
||||
*/
|
||||
struct delegpt_ns* delegpt_find_ns(struct delegpt* dp, uint8_t* name,
|
||||
size_t namelen);
|
||||
|
||||
/**
|
||||
* Find address record in total list of delegation point.
|
||||
* @param dp: delegation point.
|
||||
* @param addr: address
|
||||
* @param addrlen: length of addr
|
||||
* @return the addr structure or NULL if not found.
|
||||
*/
|
||||
struct delegpt_addr* delegpt_find_addr(struct delegpt* dp,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Print the delegation point to the log. For debugging.
|
||||
* @param v: verbosity value that is needed to emit to log.
|
||||
* @param dp: delegation point.
|
||||
*/
|
||||
void delegpt_log(enum verbosity_value v, struct delegpt* dp);
|
||||
|
||||
/** count NS and number missing for logging */
|
||||
void delegpt_count_ns(struct delegpt* dp, size_t* numns, size_t* missing);
|
||||
|
||||
/** count addresses, and number in result and available lists, for logging */
|
||||
void delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres,
|
||||
size_t* numavail);
|
||||
|
||||
/**
|
||||
* Add all usable targets to the result list.
|
||||
* @param dp: delegation point.
|
||||
*/
|
||||
void delegpt_add_unused_targets(struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* Count number of missing targets. These are ns names with no resolved flag.
|
||||
* @param dp: delegation point.
|
||||
* @return number of missing targets (or 0).
|
||||
*/
|
||||
size_t delegpt_count_missing_targets(struct delegpt* dp);
|
||||
|
||||
/** count total number of targets in dp */
|
||||
size_t delegpt_count_targets(struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* Create new delegation point from a dns message
|
||||
*
|
||||
* Note that this method does not actually test to see if the message is an
|
||||
* actual referral. It really is just checking to see if it can construct a
|
||||
* delegation point, so the message could be of some other type (some ANSWER
|
||||
* messages, some CNAME messages, generally.) Note that the resulting
|
||||
* DelegationPoint will contain targets for all "relevant" glue (i.e.,
|
||||
* address records whose ownernames match the target of one of the NS
|
||||
* records), so if policy dictates that some glue should be discarded beyond
|
||||
* that, discard it before calling this method. Note that this method will
|
||||
* find "glue" in either the ADDITIONAL section or the ANSWER section.
|
||||
*
|
||||
* @param msg: the dns message, referral.
|
||||
* @param regional: where to allocate delegation point.
|
||||
* @return new delegation point or NULL on alloc error, or if the
|
||||
* message was not appropriate.
|
||||
*/
|
||||
struct delegpt* delegpt_from_message(struct dns_msg* msg,
|
||||
struct regional* regional);
|
||||
|
||||
/**
|
||||
* Add negative message to delegation point.
|
||||
* @param dp: delegation point.
|
||||
* @param msg: the message added, marks off A or AAAA from an NS entry.
|
||||
*/
|
||||
void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg);
|
||||
|
||||
/**
|
||||
* Register the fact that there is no ipv6 and thus AAAAs are not going
|
||||
* to be queried for or be useful.
|
||||
* @param dp: the delegation point. Updated to reflect no ipv6.
|
||||
*/
|
||||
void delegpt_no_ipv6(struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* Register the fact that there is no ipv4 and thus As are not going
|
||||
* to be queried for or be useful.
|
||||
* @param dp: the delegation point. Updated to reflect no ipv4.
|
||||
*/
|
||||
void delegpt_no_ipv4(struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* create malloced delegation point, with the given name
|
||||
* @param name: uncompressed wireformat of degegpt name.
|
||||
* @return NULL on alloc failure
|
||||
*/
|
||||
struct delegpt* delegpt_create_mlc(uint8_t* name);
|
||||
|
||||
/**
|
||||
* free malloced delegation point.
|
||||
* @param dp: must have been created with delegpt_create_mlc, free'd.
|
||||
*/
|
||||
void delegpt_free_mlc(struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* Set name of delegation point.
|
||||
* @param dp: delegation point. malloced.
|
||||
* @param name: name to use.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name);
|
||||
|
||||
/**
|
||||
* add a name to malloced delegation point.
|
||||
* @param dp: must have been created with delegpt_create_mlc.
|
||||
* @param name: the name to add.
|
||||
* @param lame: the name is lame, disprefer.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, int lame);
|
||||
|
||||
/**
|
||||
* add an address to a malloced delegation point.
|
||||
* @param dp: must have been created with delegpt_create_mlc.
|
||||
* @param addr: the address.
|
||||
* @param addrlen: the length of addr.
|
||||
* @param bogus: if address is bogus.
|
||||
* @param lame: if address is lame.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int bogus, int lame);
|
||||
|
||||
/**
|
||||
* Add target address to the delegation point.
|
||||
* @param dp: must have been created with delegpt_create_mlc.
|
||||
* @param name: name for which target was found (must be in nslist).
|
||||
* This name is marked resolved.
|
||||
* @param namelen: length of name.
|
||||
* @param addr: the address.
|
||||
* @param addrlen: the length of addr.
|
||||
* @param bogus: security status for the address, pass true if bogus.
|
||||
* @param lame: address is lame.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int bogus, int lame);
|
||||
|
||||
/** get memory in use by dp */
|
||||
size_t delegpt_get_mem(struct delegpt* dp);
|
||||
|
||||
#endif /* ITERATOR_ITER_DELEGPT_H */
|
153
contrib/unbound/iterator/iter_donotq.c
Normal file
153
contrib/unbound/iterator/iter_donotq.c
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* iterator/iter_donotq.c - iterative resolver donotqueryaddresses storage.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains functions to assist the iterator module.
|
||||
* The donotqueryaddresses are stored and looked up. These addresses
|
||||
* (like 127.0.0.1) must not be used to send queries to, and can be
|
||||
* discarded immediately from the server selection.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "iterator/iter_donotq.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
|
||||
struct iter_donotq*
|
||||
donotq_create(void)
|
||||
{
|
||||
struct iter_donotq* dq = (struct iter_donotq*)calloc(1,
|
||||
sizeof(struct iter_donotq));
|
||||
if(!dq)
|
||||
return NULL;
|
||||
dq->region = regional_create();
|
||||
if(!dq->region) {
|
||||
donotq_delete(dq);
|
||||
return NULL;
|
||||
}
|
||||
return dq;
|
||||
}
|
||||
|
||||
void
|
||||
donotq_delete(struct iter_donotq* dq)
|
||||
{
|
||||
if(!dq)
|
||||
return;
|
||||
regional_destroy(dq->region);
|
||||
free(dq);
|
||||
}
|
||||
|
||||
/** insert new address into donotq structure */
|
||||
static int
|
||||
donotq_insert(struct iter_donotq* dq, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int net)
|
||||
{
|
||||
struct addr_tree_node* node = (struct addr_tree_node*)regional_alloc(
|
||||
dq->region, sizeof(*node));
|
||||
if(!node)
|
||||
return 0;
|
||||
if(!addr_tree_insert(&dq->tree, node, addr, addrlen, net)) {
|
||||
verbose(VERB_QUERY, "duplicate donotquery address ignored.");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** apply donotq string */
|
||||
static int
|
||||
donotq_str_cfg(struct iter_donotq* dq, const char* str)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
socklen_t addrlen;
|
||||
verbose(VERB_ALGO, "donotq: %s", str);
|
||||
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
|
||||
log_err("cannot parse donotquery netblock: %s", str);
|
||||
return 0;
|
||||
}
|
||||
if(!donotq_insert(dq, &addr, addrlen, net)) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** read donotq config */
|
||||
static int
|
||||
read_donotq(struct iter_donotq* dq, struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
for(p = cfg->donotqueryaddrs; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
if(!donotq_str_cfg(dq, p->str))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
|
||||
{
|
||||
regional_free_all(dq->region);
|
||||
addr_tree_init(&dq->tree);
|
||||
if(!read_donotq(dq, cfg))
|
||||
return 0;
|
||||
if(cfg->donotquery_localhost) {
|
||||
if(!donotq_str_cfg(dq, "127.0.0.0/8"))
|
||||
return 0;
|
||||
if(cfg->do_ip6) {
|
||||
if(!donotq_str_cfg(dq, "::1"))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
addr_tree_init_parents(&dq->tree);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
donotq_lookup(struct iter_donotq* donotq, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
return addr_tree_lookup(&donotq->tree, addr, addrlen) != NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
donotq_get_mem(struct iter_donotq* donotq)
|
||||
{
|
||||
if(!donotq) return 0;
|
||||
return sizeof(*donotq) + regional_get_mem(donotq->region);
|
||||
}
|
101
contrib/unbound/iterator/iter_donotq.h
Normal file
101
contrib/unbound/iterator/iter_donotq.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* iterator/iter_donotq.h - iterative resolver donotqueryaddresses storage.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains functions to assist the iterator module.
|
||||
* Keep track of the donotquery addresses and lookup fast.
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_ITER_DONOTQ_H
|
||||
#define ITERATOR_ITER_DONOTQ_H
|
||||
#include "util/storage/dnstree.h"
|
||||
struct iter_env;
|
||||
struct config_file;
|
||||
struct regional;
|
||||
|
||||
/**
|
||||
* Iterator donotqueryaddresses structure
|
||||
*/
|
||||
struct iter_donotq {
|
||||
/** regional for allocation */
|
||||
struct regional* region;
|
||||
/**
|
||||
* Tree of the address spans that are blocked.
|
||||
* contents of type addr_tree_node. Each node is an address span
|
||||
* that must not be used to send queries to.
|
||||
*/
|
||||
rbtree_t tree;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create donotqueryaddresses structure
|
||||
* @return new structure or NULL on error.
|
||||
*/
|
||||
struct iter_donotq* donotq_create(void);
|
||||
|
||||
/**
|
||||
* Delete donotqueryaddresses structure.
|
||||
* @param donotq: to delete.
|
||||
*/
|
||||
void donotq_delete(struct iter_donotq* donotq);
|
||||
|
||||
/**
|
||||
* Process donotqueryaddresses config.
|
||||
* @param donotq: where to store.
|
||||
* @param cfg: config options.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
int donotq_apply_cfg(struct iter_donotq* donotq, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* See if an address is blocked.
|
||||
* @param donotq: structure for address storage.
|
||||
* @param addr: address to check
|
||||
* @param addrlen: length of addr.
|
||||
* @return: true if the address must not be queried. false if unlisted.
|
||||
*/
|
||||
int donotq_lookup(struct iter_donotq* donotq, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Get memory used by donotqueryaddresses structure.
|
||||
* @param donotq: structure for address storage.
|
||||
* @return bytes in use.
|
||||
*/
|
||||
size_t donotq_get_mem(struct iter_donotq* donotq);
|
||||
|
||||
#endif /* ITERATOR_ITER_DONOTQ_H */
|
508
contrib/unbound/iterator/iter_fwd.c
Normal file
508
contrib/unbound/iterator/iter_fwd.c
Normal file
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* iterator/iter_fwd.c - iterative resolver module forward zones.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains functions to assist the iterator module.
|
||||
* Keep track of forward zones and config settings.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <ldns/rdata.h>
|
||||
#include <ldns/dname.h>
|
||||
#include <ldns/rr.h>
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_delegpt.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/dname.h"
|
||||
|
||||
int
|
||||
fwd_cmp(const void* k1, const void* k2)
|
||||
{
|
||||
int m;
|
||||
struct iter_forward_zone* n1 = (struct iter_forward_zone*)k1;
|
||||
struct iter_forward_zone* n2 = (struct iter_forward_zone*)k2;
|
||||
if(n1->dclass != n2->dclass) {
|
||||
if(n1->dclass < n2->dclass)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
return dname_lab_cmp(n1->name, n1->namelabs, n2->name, n2->namelabs,
|
||||
&m);
|
||||
}
|
||||
|
||||
struct iter_forwards*
|
||||
forwards_create(void)
|
||||
{
|
||||
struct iter_forwards* fwd = (struct iter_forwards*)calloc(1,
|
||||
sizeof(struct iter_forwards));
|
||||
if(!fwd)
|
||||
return NULL;
|
||||
return fwd;
|
||||
}
|
||||
|
||||
static void fwd_zone_free(struct iter_forward_zone* n)
|
||||
{
|
||||
if(!n) return;
|
||||
delegpt_free_mlc(n->dp);
|
||||
free(n->name);
|
||||
free(n);
|
||||
}
|
||||
|
||||
static void delfwdnode(rbnode_t* n, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
struct iter_forward_zone* node = (struct iter_forward_zone*)n;
|
||||
fwd_zone_free(node);
|
||||
}
|
||||
|
||||
static void fwd_del_tree(struct iter_forwards* fwd)
|
||||
{
|
||||
if(fwd->tree)
|
||||
traverse_postorder(fwd->tree, &delfwdnode, NULL);
|
||||
free(fwd->tree);
|
||||
}
|
||||
|
||||
void
|
||||
forwards_delete(struct iter_forwards* fwd)
|
||||
{
|
||||
if(!fwd)
|
||||
return;
|
||||
fwd_del_tree(fwd);
|
||||
free(fwd);
|
||||
}
|
||||
|
||||
/** insert info into forward structure */
|
||||
static int
|
||||
forwards_insert_data(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
|
||||
size_t nmlen, int nmlabs, struct delegpt* dp)
|
||||
{
|
||||
struct iter_forward_zone* node = (struct iter_forward_zone*)malloc(
|
||||
sizeof(struct iter_forward_zone));
|
||||
if(!node) {
|
||||
delegpt_free_mlc(dp);
|
||||
return 0;
|
||||
}
|
||||
node->node.key = node;
|
||||
node->dclass = c;
|
||||
node->name = memdup(nm, nmlen);
|
||||
if(!node->name) {
|
||||
delegpt_free_mlc(dp);
|
||||
free(node);
|
||||
return 0;
|
||||
}
|
||||
node->namelen = nmlen;
|
||||
node->namelabs = nmlabs;
|
||||
node->dp = dp;
|
||||
if(!rbtree_insert(fwd->tree, &node->node)) {
|
||||
log_err("duplicate forward zone ignored.");
|
||||
delegpt_free_mlc(dp);
|
||||
free(node->name);
|
||||
free(node);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** insert new info into forward structure given dp */
|
||||
static int
|
||||
forwards_insert(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp)
|
||||
{
|
||||
return forwards_insert_data(fwd, c, dp->name, dp->namelen,
|
||||
dp->namelabs, dp);
|
||||
}
|
||||
|
||||
/** initialise parent pointers in the tree */
|
||||
static void
|
||||
fwd_init_parents(struct iter_forwards* fwd)
|
||||
{
|
||||
struct iter_forward_zone* node, *prev = NULL, *p;
|
||||
int m;
|
||||
RBTREE_FOR(node, struct iter_forward_zone*, fwd->tree) {
|
||||
node->parent = NULL;
|
||||
if(!prev || prev->dclass != node->dclass) {
|
||||
prev = node;
|
||||
continue;
|
||||
}
|
||||
(void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
|
||||
node->namelabs, &m); /* we know prev is smaller */
|
||||
/* sort order like: . com. bla.com. zwb.com. net. */
|
||||
/* find the previous, or parent-parent-parent */
|
||||
for(p = prev; p; p = p->parent)
|
||||
/* looking for name with few labels, a parent */
|
||||
if(p->namelabs <= m) {
|
||||
/* ==: since prev matched m, this is closest*/
|
||||
/* <: prev matches more, but is not a parent,
|
||||
* this one is a (grand)parent */
|
||||
node->parent = p;
|
||||
break;
|
||||
}
|
||||
prev = node;
|
||||
}
|
||||
}
|
||||
|
||||
/** set zone name */
|
||||
static struct delegpt*
|
||||
read_fwds_name(struct config_stub* s)
|
||||
{
|
||||
struct delegpt* dp;
|
||||
ldns_rdf* rdf;
|
||||
if(!s->name) {
|
||||
log_err("forward zone without a name (use name \".\" to forward everything)");
|
||||
return NULL;
|
||||
}
|
||||
rdf = ldns_dname_new_frm_str(s->name);
|
||||
if(!rdf) {
|
||||
log_err("cannot parse forward zone name %s", s->name);
|
||||
return NULL;
|
||||
}
|
||||
if(!(dp=delegpt_create_mlc(ldns_rdf_data(rdf)))) {
|
||||
ldns_rdf_deep_free(rdf);
|
||||
log_err("out of memory");
|
||||
return NULL;
|
||||
}
|
||||
ldns_rdf_deep_free(rdf);
|
||||
return dp;
|
||||
}
|
||||
|
||||
/** set fwd host names */
|
||||
static int
|
||||
read_fwds_host(struct config_stub* s, struct delegpt* dp)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
ldns_rdf* rdf;
|
||||
for(p = s->hosts; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
rdf = ldns_dname_new_frm_str(p->str);
|
||||
if(!rdf) {
|
||||
log_err("cannot parse forward %s server name: '%s'",
|
||||
s->name, p->str);
|
||||
return 0;
|
||||
}
|
||||
if(!delegpt_add_ns_mlc(dp, ldns_rdf_data(rdf), 0)) {
|
||||
ldns_rdf_deep_free(rdf);
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
ldns_rdf_deep_free(rdf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** set fwd server addresses */
|
||||
static int
|
||||
read_fwds_addr(struct config_stub* s, struct delegpt* dp)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
for(p = s->addrs; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
if(!extstrtoaddr(p->str, &addr, &addrlen)) {
|
||||
log_err("cannot parse forward %s ip address: '%s'",
|
||||
s->name, p->str);
|
||||
return 0;
|
||||
}
|
||||
if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0)) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** read forwards config */
|
||||
static int
|
||||
read_forwards(struct iter_forwards* fwd, struct config_file* cfg)
|
||||
{
|
||||
struct config_stub* s;
|
||||
for(s = cfg->forwards; s; s = s->next) {
|
||||
struct delegpt* dp;
|
||||
if(!(dp=read_fwds_name(s)) ||
|
||||
!read_fwds_host(s, dp) ||
|
||||
!read_fwds_addr(s, dp))
|
||||
return 0;
|
||||
/* set flag that parent side NS information is included.
|
||||
* Asking a (higher up) server on the internet is not useful */
|
||||
/* the flag is turned off for 'forward-first' so that the
|
||||
* last resort will ask for parent-side NS record and thus
|
||||
* fallback to the internet name servers on a failure */
|
||||
dp->has_parent_side_NS = (uint8_t)!s->isfirst;
|
||||
if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp))
|
||||
return 0;
|
||||
verbose(VERB_QUERY, "Forward zone server list:");
|
||||
delegpt_log(VERB_QUERY, dp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** see if zone needs to have a hole inserted */
|
||||
static int
|
||||
need_hole_insert(rbtree_t* tree, struct iter_forward_zone* zone)
|
||||
{
|
||||
struct iter_forward_zone k;
|
||||
if(rbtree_search(tree, zone))
|
||||
return 0; /* exact match exists */
|
||||
k = *zone;
|
||||
k.node.key = &k;
|
||||
/* search up the tree */
|
||||
do {
|
||||
dname_remove_label(&k.name, &k.namelen);
|
||||
k.namelabs --;
|
||||
if(rbtree_search(tree, &k))
|
||||
return 1; /* found an upper forward zone, need hole */
|
||||
} while(k.namelabs > 1);
|
||||
return 0; /* no forwards above, no holes needed */
|
||||
}
|
||||
|
||||
/** insert a stub hole (if necessary) for stub name */
|
||||
static int
|
||||
fwd_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
struct iter_forward_zone key;
|
||||
key.node.key = &key;
|
||||
key.dclass = c;
|
||||
key.name = nm;
|
||||
key.namelabs = dname_count_size_labels(key.name, &key.namelen);
|
||||
if(need_hole_insert(fwd->tree, &key)) {
|
||||
return forwards_insert_data(fwd, key.dclass, key.name,
|
||||
key.namelen, key.namelabs, NULL);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** make NULL entries for stubs */
|
||||
static int
|
||||
make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg)
|
||||
{
|
||||
struct config_stub* s;
|
||||
for(s = cfg->stubs; s; s = s->next) {
|
||||
ldns_rdf* rdf = ldns_dname_new_frm_str(s->name);
|
||||
if(!rdf) {
|
||||
log_err("cannot parse stub name '%s'", s->name);
|
||||
return 0;
|
||||
}
|
||||
if(!fwd_add_stub_hole(fwd, LDNS_RR_CLASS_IN,
|
||||
ldns_rdf_data(rdf))) {
|
||||
ldns_rdf_deep_free(rdf);
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
ldns_rdf_deep_free(rdf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg)
|
||||
{
|
||||
fwd_del_tree(fwd);
|
||||
fwd->tree = rbtree_create(fwd_cmp);
|
||||
if(!fwd->tree)
|
||||
return 0;
|
||||
|
||||
/* read forward zones */
|
||||
if(!read_forwards(fwd, cfg))
|
||||
return 0;
|
||||
if(!make_stub_holes(fwd, cfg))
|
||||
return 0;
|
||||
fwd_init_parents(fwd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
|
||||
{
|
||||
/* lookup the forward zone in the tree */
|
||||
rbnode_t* res = NULL;
|
||||
struct iter_forward_zone *result;
|
||||
struct iter_forward_zone key;
|
||||
key.node.key = &key;
|
||||
key.dclass = qclass;
|
||||
key.name = qname;
|
||||
key.namelabs = dname_count_size_labels(qname, &key.namelen);
|
||||
if(rbtree_find_less_equal(fwd->tree, &key, &res)) {
|
||||
/* exact */
|
||||
result = (struct iter_forward_zone*)res;
|
||||
} else {
|
||||
/* smaller element (or no element) */
|
||||
int m;
|
||||
result = (struct iter_forward_zone*)res;
|
||||
if(!result || result->dclass != qclass)
|
||||
return NULL;
|
||||
/* count number of labels matched */
|
||||
(void)dname_lab_cmp(result->name, result->namelabs, key.name,
|
||||
key.namelabs, &m);
|
||||
while(result) { /* go up until qname is subdomain of stub */
|
||||
if(result->namelabs <= m)
|
||||
break;
|
||||
result = result->parent;
|
||||
}
|
||||
}
|
||||
if(result)
|
||||
return result->dp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
forwards_lookup_root(struct iter_forwards* fwd, uint16_t qclass)
|
||||
{
|
||||
uint8_t root = 0;
|
||||
return forwards_lookup(fwd, &root, qclass);
|
||||
}
|
||||
|
||||
int
|
||||
forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass)
|
||||
{
|
||||
struct iter_forward_zone key;
|
||||
rbnode_t* n;
|
||||
struct iter_forward_zone* p;
|
||||
if(*dclass == 0) {
|
||||
/* first root item is first item in tree */
|
||||
n = rbtree_first(fwd->tree);
|
||||
if(n == RBTREE_NULL)
|
||||
return 0;
|
||||
p = (struct iter_forward_zone*)n;
|
||||
if(dname_is_root(p->name)) {
|
||||
*dclass = p->dclass;
|
||||
return 1;
|
||||
}
|
||||
/* root not first item? search for higher items */
|
||||
*dclass = p->dclass + 1;
|
||||
return forwards_next_root(fwd, dclass);
|
||||
}
|
||||
/* find class n in tree, we may get a direct hit, or if we don't
|
||||
* this is the last item of the previous class so rbtree_next() takes
|
||||
* us to the next root (if any) */
|
||||
key.node.key = &key;
|
||||
key.name = (uint8_t*)"\000";
|
||||
key.namelen = 1;
|
||||
key.namelabs = 0;
|
||||
key.dclass = *dclass;
|
||||
n = NULL;
|
||||
if(rbtree_find_less_equal(fwd->tree, &key, &n)) {
|
||||
/* exact */
|
||||
return 1;
|
||||
} else {
|
||||
/* smaller element */
|
||||
if(!n || n == RBTREE_NULL)
|
||||
return 0; /* nothing found */
|
||||
n = rbtree_next(n);
|
||||
if(n == RBTREE_NULL)
|
||||
return 0; /* no higher */
|
||||
p = (struct iter_forward_zone*)n;
|
||||
if(dname_is_root(p->name)) {
|
||||
*dclass = p->dclass;
|
||||
return 1;
|
||||
}
|
||||
/* not a root node, return next higher item */
|
||||
*dclass = p->dclass+1;
|
||||
return forwards_next_root(fwd, dclass);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
forwards_get_mem(struct iter_forwards* fwd)
|
||||
{
|
||||
struct iter_forward_zone* p;
|
||||
size_t s;
|
||||
if(!fwd)
|
||||
return 0;
|
||||
s = sizeof(*fwd) + sizeof(*fwd->tree);
|
||||
RBTREE_FOR(p, struct iter_forward_zone*, fwd->tree) {
|
||||
s += sizeof(*p) + p->namelen + delegpt_get_mem(p->dp);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static struct iter_forward_zone*
|
||||
fwd_zone_find(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
struct iter_forward_zone key;
|
||||
key.node.key = &key;
|
||||
key.dclass = c;
|
||||
key.name = nm;
|
||||
key.namelabs = dname_count_size_labels(nm, &key.namelen);
|
||||
return (struct iter_forward_zone*)rbtree_search(fwd->tree, &key);
|
||||
}
|
||||
|
||||
int
|
||||
forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp)
|
||||
{
|
||||
struct iter_forward_zone *z;
|
||||
if((z=fwd_zone_find(fwd, c, dp->name)) != NULL) {
|
||||
(void)rbtree_delete(fwd->tree, &z->node);
|
||||
fwd_zone_free(z);
|
||||
}
|
||||
if(!forwards_insert(fwd, c, dp))
|
||||
return 0;
|
||||
fwd_init_parents(fwd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
struct iter_forward_zone *z;
|
||||
if(!(z=fwd_zone_find(fwd, c, nm)))
|
||||
return; /* nothing to do */
|
||||
(void)rbtree_delete(fwd->tree, &z->node);
|
||||
fwd_zone_free(z);
|
||||
fwd_init_parents(fwd);
|
||||
}
|
||||
|
||||
int
|
||||
forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
if(!fwd_add_stub_hole(fwd, c, nm)) {
|
||||
return 0;
|
||||
}
|
||||
fwd_init_parents(fwd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
struct iter_forward_zone *z;
|
||||
if(!(z=fwd_zone_find(fwd, c, nm)))
|
||||
return; /* nothing to do */
|
||||
if(z->dp != NULL)
|
||||
return; /* not a stub hole */
|
||||
(void)rbtree_delete(fwd->tree, &z->node);
|
||||
fwd_zone_free(z);
|
||||
fwd_init_parents(fwd);
|
||||
}
|
||||
|
189
contrib/unbound/iterator/iter_fwd.h
Normal file
189
contrib/unbound/iterator/iter_fwd.h
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* iterator/iter_fwd.h - iterative resolver module forward zones.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains functions to assist the iterator module.
|
||||
* Keep track of forward zones, and read those from config.
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_ITER_FWD_H
|
||||
#define ITERATOR_ITER_FWD_H
|
||||
#include "util/rbtree.h"
|
||||
struct config_file;
|
||||
struct delegpt;
|
||||
|
||||
/**
|
||||
* Iterator forward zones structure
|
||||
*/
|
||||
struct iter_forwards {
|
||||
/**
|
||||
* Zones are stored in this tree. Sort order is specially chosen.
|
||||
* first sorted on qclass. Then on dname in nsec-like order, so that
|
||||
* a lookup on class, name will return an exact match or the closest
|
||||
* match which gives the ancestor needed.
|
||||
* contents of type iter_forward_zone.
|
||||
*/
|
||||
rbtree_t* tree;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterator forward servers for a particular zone.
|
||||
*/
|
||||
struct iter_forward_zone {
|
||||
/** redblacktree node, key is this structure: class and name */
|
||||
rbnode_t node;
|
||||
/** name */
|
||||
uint8_t* name;
|
||||
/** length of name */
|
||||
size_t namelen;
|
||||
/** number of labels in name */
|
||||
int namelabs;
|
||||
/** delegation point with forward server information for this zone.
|
||||
* If NULL then this forward entry is used to indicate that a
|
||||
* stub-zone with the same name exists, and should be used.
|
||||
* This delegation point is malloced.
|
||||
*/
|
||||
struct delegpt* dp;
|
||||
/** pointer to parent in tree (or NULL if none) */
|
||||
struct iter_forward_zone* parent;
|
||||
/** class. host order. */
|
||||
uint16_t dclass;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create forwards
|
||||
* @return new forwards or NULL on error.
|
||||
*/
|
||||
struct iter_forwards* forwards_create(void);
|
||||
|
||||
/**
|
||||
* Delete forwards.
|
||||
* @param fwd: to delete.
|
||||
*/
|
||||
void forwards_delete(struct iter_forwards* fwd);
|
||||
|
||||
/**
|
||||
* Process forwards config.
|
||||
* @param fwd: where to store.
|
||||
* @param cfg: config options.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
int forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Find forward zone information
|
||||
* For this qname/qclass find forward zone information, returns delegation
|
||||
* point with server names and addresses, or NULL if no forwarding is needed.
|
||||
*
|
||||
* @param fwd: forward storage.
|
||||
* @param qname: The qname of the query.
|
||||
* @param qclass: The qclass of the query.
|
||||
* @return: A delegation point if the query has to be forwarded to that list,
|
||||
* otherwise null.
|
||||
*/
|
||||
struct delegpt* forwards_lookup(struct iter_forwards* fwd,
|
||||
uint8_t* qname, uint16_t qclass);
|
||||
|
||||
/**
|
||||
* Same as forwards_lookup, but for the root only
|
||||
* @param fwd: forward storage.
|
||||
* @param qclass: The qclass of the query.
|
||||
* @return: A delegation point if root forward exists, otherwise null.
|
||||
*/
|
||||
struct delegpt* forwards_lookup_root(struct iter_forwards* fwd,
|
||||
uint16_t qclass);
|
||||
|
||||
/**
|
||||
* Find next root item in forwards lookup tree.
|
||||
* @param fwd: the forward storage
|
||||
* @param qclass: class to look at next, or higher.
|
||||
* @return false if none found, or if true stored in qclass.
|
||||
*/
|
||||
int forwards_next_root(struct iter_forwards* fwd, uint16_t* qclass);
|
||||
|
||||
/**
|
||||
* Get memory in use by forward storage
|
||||
* @param fwd: forward storage.
|
||||
* @return bytes in use
|
||||
*/
|
||||
size_t forwards_get_mem(struct iter_forwards* fwd);
|
||||
|
||||
/** compare two fwd entries */
|
||||
int fwd_cmp(const void* k1, const void* k2);
|
||||
|
||||
/**
|
||||
* Add zone to forward structure. For external use since it recalcs
|
||||
* the tree parents.
|
||||
* @param fwd: the forward data structure
|
||||
* @param c: class of zone
|
||||
* @param dp: delegation point with name and target nameservers for new
|
||||
* forward zone. malloced.
|
||||
* @return false on failure (out of memory);
|
||||
*/
|
||||
int forwards_add_zone(struct iter_forwards* fwd, uint16_t c,
|
||||
struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* Remove zone from forward structure. For external use since it
|
||||
* recalcs the tree parents.
|
||||
* @param fwd: the forward data structure
|
||||
* @param c: class of zone
|
||||
* @param nm: name of zone (in uncompressed wireformat).
|
||||
*/
|
||||
void forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm);
|
||||
|
||||
/**
|
||||
* Add stub hole (empty entry in forward table, that makes resolution skip
|
||||
* a forward-zone because the stub zone should override the forward zone).
|
||||
* Does not add one if not necessary.
|
||||
* @param fwd: the forward data structure
|
||||
* @param c: class of zone
|
||||
* @param nm: name of zone (in uncompressed wireformat).
|
||||
* @return false on failure (out of memory);
|
||||
*/
|
||||
int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm);
|
||||
|
||||
/**
|
||||
* Remove stub hole, if one exists.
|
||||
* @param fwd: the forward data structure
|
||||
* @param c: class of zone
|
||||
* @param nm: name of zone (in uncompressed wireformat).
|
||||
*/
|
||||
void forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
|
||||
uint8_t* nm);
|
||||
|
||||
#endif /* ITERATOR_ITER_FWD_H */
|
534
contrib/unbound/iterator/iter_hints.c
Normal file
534
contrib/unbound/iterator/iter_hints.c
Normal file
@ -0,0 +1,534 @@
|
||||
/*
|
||||
* iterator/iter_hints.c - iterative resolver module stub and root hints.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains functions to assist the iterator module.
|
||||
* Keep track of stub and root hints, and read those from config.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <ldns/dname.h>
|
||||
#include <ldns/rr.h>
|
||||
#include "iterator/iter_hints.h"
|
||||
#include "iterator/iter_delegpt.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/dname.h"
|
||||
|
||||
struct iter_hints*
|
||||
hints_create(void)
|
||||
{
|
||||
struct iter_hints* hints = (struct iter_hints*)calloc(1,
|
||||
sizeof(struct iter_hints));
|
||||
if(!hints)
|
||||
return NULL;
|
||||
return hints;
|
||||
}
|
||||
|
||||
static void hints_stub_free(struct iter_hints_stub* s)
|
||||
{
|
||||
if(!s) return;
|
||||
delegpt_free_mlc(s->dp);
|
||||
free(s);
|
||||
}
|
||||
|
||||
static void delhintnode(rbnode_t* n, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
struct iter_hints_stub* node = (struct iter_hints_stub*)n;
|
||||
hints_stub_free(node);
|
||||
}
|
||||
|
||||
static void hints_del_tree(struct iter_hints* hints)
|
||||
{
|
||||
traverse_postorder(&hints->tree, &delhintnode, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
hints_delete(struct iter_hints* hints)
|
||||
{
|
||||
if(!hints)
|
||||
return;
|
||||
hints_del_tree(hints);
|
||||
free(hints);
|
||||
}
|
||||
|
||||
/** add hint to delegation hints */
|
||||
static int
|
||||
ah(struct delegpt* dp, const char* sv, const char* ip)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
ldns_rdf* rdf = ldns_dname_new_frm_str(sv);
|
||||
if(!rdf) {
|
||||
log_err("could not parse %s", sv);
|
||||
return 0;
|
||||
}
|
||||
if(!delegpt_add_ns_mlc(dp, ldns_rdf_data(rdf), 0) ||
|
||||
!extstrtoaddr(ip, &addr, &addrlen) ||
|
||||
!delegpt_add_target_mlc(dp, ldns_rdf_data(rdf), ldns_rdf_size(rdf),
|
||||
&addr, addrlen, 0, 0)) {
|
||||
ldns_rdf_deep_free(rdf);
|
||||
return 0;
|
||||
}
|
||||
ldns_rdf_deep_free(rdf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** obtain compiletime provided root hints */
|
||||
static struct delegpt*
|
||||
compile_time_root_prime(int do_ip4, int do_ip6)
|
||||
{
|
||||
/* from:
|
||||
; This file is made available by InterNIC
|
||||
; under anonymous FTP as
|
||||
; file /domain/named.cache
|
||||
; on server FTP.INTERNIC.NET
|
||||
; -OR- RS.INTERNIC.NET
|
||||
;
|
||||
; related version of root zone: 2010061700
|
||||
*/
|
||||
struct delegpt* dp = delegpt_create_mlc((uint8_t*)"\000");
|
||||
if(!dp)
|
||||
return NULL;
|
||||
dp->has_parent_side_NS = 1;
|
||||
if(do_ip4) {
|
||||
if(!ah(dp, "A.ROOT-SERVERS.NET.", "198.41.0.4")) return 0;
|
||||
if(!ah(dp, "B.ROOT-SERVERS.NET.", "192.228.79.201")) return 0;
|
||||
if(!ah(dp, "C.ROOT-SERVERS.NET.", "192.33.4.12")) return 0;
|
||||
if(!ah(dp, "D.ROOT-SERVERS.NET.", "128.8.10.90")) return 0;
|
||||
if(!ah(dp, "E.ROOT-SERVERS.NET.", "192.203.230.10")) return 0;
|
||||
if(!ah(dp, "F.ROOT-SERVERS.NET.", "192.5.5.241")) return 0;
|
||||
if(!ah(dp, "G.ROOT-SERVERS.NET.", "192.112.36.4")) return 0;
|
||||
if(!ah(dp, "H.ROOT-SERVERS.NET.", "128.63.2.53")) return 0;
|
||||
if(!ah(dp, "I.ROOT-SERVERS.NET.", "192.36.148.17")) return 0;
|
||||
if(!ah(dp, "J.ROOT-SERVERS.NET.", "192.58.128.30")) return 0;
|
||||
if(!ah(dp, "K.ROOT-SERVERS.NET.", "193.0.14.129")) return 0;
|
||||
if(!ah(dp, "L.ROOT-SERVERS.NET.", "199.7.83.42")) return 0;
|
||||
if(!ah(dp, "M.ROOT-SERVERS.NET.", "202.12.27.33")) return 0;
|
||||
}
|
||||
if(do_ip6) {
|
||||
if(!ah(dp, "A.ROOT-SERVERS.NET.", "2001:503:ba3e::2:30")) return 0;
|
||||
if(!ah(dp, "D.ROOT-SERVERS.NET.", "2001:500:2d::d")) return 0;
|
||||
if(!ah(dp, "F.ROOT-SERVERS.NET.", "2001:500:2f::f")) return 0;
|
||||
if(!ah(dp, "H.ROOT-SERVERS.NET.", "2001:500:1::803f:235")) return 0;
|
||||
if(!ah(dp, "I.ROOT-SERVERS.NET.", "2001:7fe::53")) return 0;
|
||||
if(!ah(dp, "J.ROOT-SERVERS.NET.", "2001:503:c27::2:30")) return 0;
|
||||
if(!ah(dp, "K.ROOT-SERVERS.NET.", "2001:7fd::1")) return 0;
|
||||
if(!ah(dp, "L.ROOT-SERVERS.NET.", "2001:500:3::42")) return 0;
|
||||
if(!ah(dp, "M.ROOT-SERVERS.NET.", "2001:dc3::35")) return 0;
|
||||
}
|
||||
return dp;
|
||||
}
|
||||
|
||||
/** insert new hint info into hint structure */
|
||||
static int
|
||||
hints_insert(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
|
||||
int noprime)
|
||||
{
|
||||
struct iter_hints_stub* node = (struct iter_hints_stub*)malloc(
|
||||
sizeof(struct iter_hints_stub));
|
||||
if(!node) {
|
||||
delegpt_free_mlc(dp);
|
||||
return 0;
|
||||
}
|
||||
node->dp = dp;
|
||||
node->noprime = (uint8_t)noprime;
|
||||
if(!name_tree_insert(&hints->tree, &node->node, dp->name, dp->namelen,
|
||||
dp->namelabs, c)) {
|
||||
log_err("second hints ignored.");
|
||||
delegpt_free_mlc(dp);
|
||||
free(node);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** set stub name */
|
||||
static struct delegpt*
|
||||
read_stubs_name(struct config_stub* s)
|
||||
{
|
||||
struct delegpt* dp;
|
||||
ldns_rdf* rdf;
|
||||
if(!s->name) {
|
||||
log_err("stub zone without a name");
|
||||
return NULL;
|
||||
}
|
||||
rdf = ldns_dname_new_frm_str(s->name);
|
||||
if(!rdf) {
|
||||
log_err("cannot parse stub zone name %s", s->name);
|
||||
return NULL;
|
||||
}
|
||||
if(!(dp=delegpt_create_mlc(ldns_rdf_data(rdf)))) {
|
||||
ldns_rdf_deep_free(rdf);
|
||||
log_err("out of memory");
|
||||
return NULL;
|
||||
}
|
||||
ldns_rdf_deep_free(rdf);
|
||||
return dp;
|
||||
}
|
||||
|
||||
/** set stub host names */
|
||||
static int
|
||||
read_stubs_host(struct config_stub* s, struct delegpt* dp)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
ldns_rdf* rdf;
|
||||
for(p = s->hosts; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
rdf = ldns_dname_new_frm_str(p->str);
|
||||
if(!rdf) {
|
||||
log_err("cannot parse stub %s nameserver name: '%s'",
|
||||
s->name, p->str);
|
||||
return 0;
|
||||
}
|
||||
if(!delegpt_add_ns_mlc(dp, ldns_rdf_data(rdf), 0)) {
|
||||
ldns_rdf_deep_free(rdf);
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
ldns_rdf_deep_free(rdf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** set stub server addresses */
|
||||
static int
|
||||
read_stubs_addr(struct config_stub* s, struct delegpt* dp)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
for(p = s->addrs; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
if(!extstrtoaddr(p->str, &addr, &addrlen)) {
|
||||
log_err("cannot parse stub %s ip address: '%s'",
|
||||
s->name, p->str);
|
||||
return 0;
|
||||
}
|
||||
if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0)) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** read stubs config */
|
||||
static int
|
||||
read_stubs(struct iter_hints* hints, struct config_file* cfg)
|
||||
{
|
||||
struct config_stub* s;
|
||||
struct delegpt* dp;
|
||||
for(s = cfg->stubs; s; s = s->next) {
|
||||
if(!(dp=read_stubs_name(s)) ||
|
||||
!read_stubs_host(s, dp) ||
|
||||
!read_stubs_addr(s, dp))
|
||||
return 0;
|
||||
/* the flag is turned off for 'stub-first' so that the
|
||||
* last resort will ask for parent-side NS record and thus
|
||||
* fallback to the internet name servers on a failure */
|
||||
dp->has_parent_side_NS = (uint8_t)!s->isfirst;
|
||||
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime))
|
||||
return 0;
|
||||
delegpt_log(VERB_QUERY, dp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** read root hints from file */
|
||||
static int
|
||||
read_root_hints(struct iter_hints* hints, char* fname)
|
||||
{
|
||||
int lineno = 0;
|
||||
uint32_t default_ttl = 0;
|
||||
ldns_rdf* origin = NULL;
|
||||
ldns_rdf* prev_rr = NULL;
|
||||
struct delegpt* dp;
|
||||
ldns_rr* rr = NULL;
|
||||
ldns_status status;
|
||||
uint16_t c = LDNS_RR_CLASS_IN;
|
||||
FILE* f = fopen(fname, "r");
|
||||
if(!f) {
|
||||
log_err("could not read root hints %s: %s",
|
||||
fname, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
dp = delegpt_create_mlc(NULL);
|
||||
if(!dp) {
|
||||
log_err("out of memory reading root hints");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_QUERY, "Reading root hints from %s", fname);
|
||||
dp->has_parent_side_NS = 1;
|
||||
while(!feof(f)) {
|
||||
status = ldns_rr_new_frm_fp_l(&rr, f,
|
||||
&default_ttl, &origin, &prev_rr, &lineno);
|
||||
if(status == LDNS_STATUS_SYNTAX_EMPTY ||
|
||||
status == LDNS_STATUS_SYNTAX_TTL ||
|
||||
status == LDNS_STATUS_SYNTAX_ORIGIN)
|
||||
continue;
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("reading root hints %s %d: %s", fname,
|
||||
lineno, ldns_get_errorstr_by_id(status));
|
||||
goto stop_read;
|
||||
}
|
||||
if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS) {
|
||||
if(!delegpt_add_ns_mlc(dp,
|
||||
ldns_rdf_data(ldns_rr_rdf(rr, 0)), 0)) {
|
||||
log_err("out of memory reading root hints");
|
||||
goto stop_read;
|
||||
}
|
||||
c = ldns_rr_get_class(rr);
|
||||
if(!dp->name) {
|
||||
if(!delegpt_set_name_mlc(dp,
|
||||
ldns_rdf_data(ldns_rr_owner(rr)))){
|
||||
log_err("out of memory.");
|
||||
goto stop_read;
|
||||
}
|
||||
}
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_A) {
|
||||
struct sockaddr_in sa;
|
||||
socklen_t len = (socklen_t)sizeof(sa);
|
||||
memset(&sa, 0, len);
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
memmove(&sa.sin_addr,
|
||||
ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET_SIZE);
|
||||
if(!delegpt_add_target_mlc(dp,
|
||||
ldns_rdf_data(ldns_rr_owner(rr)),
|
||||
ldns_rdf_size(ldns_rr_owner(rr)),
|
||||
(struct sockaddr_storage*)&sa, len,
|
||||
0, 0)) {
|
||||
log_err("out of memory reading root hints");
|
||||
goto stop_read;
|
||||
}
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) {
|
||||
struct sockaddr_in6 sa;
|
||||
socklen_t len = (socklen_t)sizeof(sa);
|
||||
memset(&sa, 0, len);
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
memmove(&sa.sin6_addr,
|
||||
ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET6_SIZE);
|
||||
if(!delegpt_add_target_mlc(dp,
|
||||
ldns_rdf_data(ldns_rr_owner(rr)),
|
||||
ldns_rdf_size(ldns_rr_owner(rr)),
|
||||
(struct sockaddr_storage*)&sa, len,
|
||||
0, 0)) {
|
||||
log_err("out of memory reading root hints");
|
||||
goto stop_read;
|
||||
}
|
||||
} else {
|
||||
log_warn("root hints %s:%d skipping type %d",
|
||||
fname, lineno, ldns_rr_get_type(rr));
|
||||
}
|
||||
|
||||
ldns_rr_free(rr);
|
||||
}
|
||||
|
||||
if (origin)
|
||||
ldns_rdf_deep_free(origin);
|
||||
if (prev_rr)
|
||||
ldns_rdf_deep_free(prev_rr);
|
||||
fclose(f);
|
||||
if(!dp->name) {
|
||||
log_warn("root hints %s: no NS content", fname);
|
||||
delegpt_free_mlc(dp);
|
||||
return 1;
|
||||
}
|
||||
if(!hints_insert(hints, c, dp, 0)) {
|
||||
return 0;
|
||||
}
|
||||
delegpt_log(VERB_QUERY, dp);
|
||||
return 1;
|
||||
|
||||
stop_read:
|
||||
if (origin)
|
||||
ldns_rdf_deep_free(origin);
|
||||
if (prev_rr)
|
||||
ldns_rdf_deep_free(prev_rr);
|
||||
delegpt_free_mlc(dp);
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** read root hints list */
|
||||
static int
|
||||
read_root_hints_list(struct iter_hints* hints, struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
for(p = cfg->root_hints; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
if(p->str && p->str[0]) {
|
||||
char* f = p->str;
|
||||
if(cfg->chrootdir && cfg->chrootdir[0] &&
|
||||
strncmp(p->str, cfg->chrootdir,
|
||||
strlen(cfg->chrootdir)) == 0)
|
||||
f += strlen(cfg->chrootdir);
|
||||
if(!read_root_hints(hints, f))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
|
||||
{
|
||||
hints_del_tree(hints);
|
||||
name_tree_init(&hints->tree);
|
||||
|
||||
/* read root hints */
|
||||
if(!read_root_hints_list(hints, cfg))
|
||||
return 0;
|
||||
|
||||
/* read stub hints */
|
||||
if(!read_stubs(hints, cfg))
|
||||
return 0;
|
||||
|
||||
/* use fallback compiletime root hints */
|
||||
if(!hints_lookup_root(hints, LDNS_RR_CLASS_IN)) {
|
||||
struct delegpt* dp = compile_time_root_prime(cfg->do_ip4,
|
||||
cfg->do_ip6);
|
||||
verbose(VERB_ALGO, "no config, using builtin root hints.");
|
||||
if(!dp)
|
||||
return 0;
|
||||
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0))
|
||||
return 0;
|
||||
}
|
||||
|
||||
name_tree_init_parents(&hints->tree);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
hints_lookup_root(struct iter_hints* hints, uint16_t qclass)
|
||||
{
|
||||
uint8_t rootlab = 0;
|
||||
struct iter_hints_stub *stub;
|
||||
stub = (struct iter_hints_stub*)name_tree_find(&hints->tree,
|
||||
&rootlab, 1, 1, qclass);
|
||||
if(!stub)
|
||||
return NULL;
|
||||
return stub->dp;
|
||||
}
|
||||
|
||||
struct iter_hints_stub*
|
||||
hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
|
||||
uint16_t qclass, struct delegpt* cache_dp)
|
||||
{
|
||||
size_t len;
|
||||
int labs;
|
||||
struct iter_hints_stub *r;
|
||||
|
||||
/* first lookup the stub */
|
||||
labs = dname_count_size_labels(qname, &len);
|
||||
r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname,
|
||||
len, labs, qclass);
|
||||
if(!r) return NULL;
|
||||
|
||||
/* If there is no cache (root prime situation) */
|
||||
if(cache_dp == NULL) {
|
||||
if(r->dp->namelabs != 1)
|
||||
return r; /* no cache dp, use any non-root stub */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the stub is same as the delegation we got
|
||||
* And has noprime set, we need to 'prime' to use this stub instead.
|
||||
*/
|
||||
if(r->noprime && query_dname_compare(cache_dp->name, r->dp->name)==0)
|
||||
return r; /* use this stub instead of cached dp */
|
||||
|
||||
/*
|
||||
* If our cached delegation point is above the hint, we need to prime.
|
||||
*/
|
||||
if(dname_strict_subdomain(r->dp->name, r->dp->namelabs,
|
||||
cache_dp->name, cache_dp->namelabs))
|
||||
return r; /* need to prime this stub */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hints_next_root(struct iter_hints* hints, uint16_t* qclass)
|
||||
{
|
||||
return name_tree_next_root(&hints->tree, qclass);
|
||||
}
|
||||
|
||||
size_t
|
||||
hints_get_mem(struct iter_hints* hints)
|
||||
{
|
||||
size_t s;
|
||||
struct iter_hints_stub* p;
|
||||
if(!hints) return 0;
|
||||
s = sizeof(*hints);
|
||||
RBTREE_FOR(p, struct iter_hints_stub*, &hints->tree) {
|
||||
s += sizeof(*p) + delegpt_get_mem(p->dp);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
|
||||
int noprime)
|
||||
{
|
||||
struct iter_hints_stub *z;
|
||||
if((z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
|
||||
dp->name, dp->namelen, dp->namelabs, c)) != NULL) {
|
||||
(void)rbtree_delete(&hints->tree, &z->node);
|
||||
hints_stub_free(z);
|
||||
}
|
||||
if(!hints_insert(hints, c, dp, noprime))
|
||||
return 0;
|
||||
name_tree_init_parents(&hints->tree);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
struct iter_hints_stub *z;
|
||||
size_t len;
|
||||
int labs = dname_count_size_labels(nm, &len);
|
||||
if(!(z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
|
||||
nm, len, labs, c)))
|
||||
return; /* nothing to do */
|
||||
(void)rbtree_delete(&hints->tree, &z->node);
|
||||
hints_stub_free(z);
|
||||
name_tree_init_parents(&hints->tree);
|
||||
}
|
||||
|
161
contrib/unbound/iterator/iter_hints.h
Normal file
161
contrib/unbound/iterator/iter_hints.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* iterator/iter_hints.h - iterative resolver module stub and root hints.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains functions to assist the iterator module.
|
||||
* Keep track of stub and root hints, and read those from config.
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_ITER_HINTS_H
|
||||
#define ITERATOR_ITER_HINTS_H
|
||||
#include "util/storage/dnstree.h"
|
||||
struct iter_env;
|
||||
struct config_file;
|
||||
struct delegpt;
|
||||
|
||||
/**
|
||||
* Iterator hints structure
|
||||
*/
|
||||
struct iter_hints {
|
||||
/**
|
||||
* Hints are stored in this tree. Sort order is specially chosen.
|
||||
* first sorted on qclass. Then on dname in nsec-like order, so that
|
||||
* a lookup on class, name will return an exact match or the closest
|
||||
* match which gives the ancestor needed.
|
||||
* contents of type iter_hints_stub. The class IN root is in here.
|
||||
* uses name_tree_node from dnstree.h.
|
||||
*/
|
||||
rbtree_t tree;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterator hints for a particular stub.
|
||||
*/
|
||||
struct iter_hints_stub {
|
||||
/** tree sorted by name, class */
|
||||
struct name_tree_node node;
|
||||
/** delegation point with hint information for this stub. malloced. */
|
||||
struct delegpt* dp;
|
||||
/** does the stub need to forego priming (like on other ports) */
|
||||
uint8_t noprime;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create hints
|
||||
* @return new hints or NULL on error.
|
||||
*/
|
||||
struct iter_hints* hints_create(void);
|
||||
|
||||
/**
|
||||
* Delete hints.
|
||||
* @param hints: to delete.
|
||||
*/
|
||||
void hints_delete(struct iter_hints* hints);
|
||||
|
||||
/**
|
||||
* Process hints config. Sets default values for root hints if no config.
|
||||
* @param hints: where to store.
|
||||
* @param cfg: config options.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
int hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Find root hints for the given class.
|
||||
* @param hints: hint storage.
|
||||
* @param qclass: class for which root hints are requested. host order.
|
||||
* @return: NULL if no hints, or a ptr to stored hints.
|
||||
*/
|
||||
struct delegpt* hints_lookup_root(struct iter_hints* hints, uint16_t qclass);
|
||||
|
||||
/**
|
||||
* Find next root hints (to cycle through all root hints).
|
||||
* @param hints: hint storage
|
||||
* @param qclass: class for which root hints are sought.
|
||||
* 0 means give the first available root hints class.
|
||||
* x means, give class x or a higher class if any.
|
||||
* returns the found class in this variable.
|
||||
* @return true if a root hint class is found.
|
||||
* false if not root hint class is found (qclass may have been changed).
|
||||
*/
|
||||
int hints_next_root(struct iter_hints* hints, uint16_t* qclass);
|
||||
|
||||
/**
|
||||
* Given a qname/qclass combination, and the delegation point from the cache
|
||||
* for this qname/qclass, determine if this combination indicates that a
|
||||
* stub hint exists and must be primed.
|
||||
*
|
||||
* @param hints: hint storage.
|
||||
* @param qname: The qname that generated the delegation point.
|
||||
* @param qclass: The qclass that generated the delegation point.
|
||||
* @param dp: The cache generated delegation point.
|
||||
* @return: A priming delegation point if there is a stub hint that must
|
||||
* be primed, otherwise null.
|
||||
*/
|
||||
struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints,
|
||||
uint8_t* qname, uint16_t qclass, struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* Get memory in use by hints
|
||||
* @param hints: hint storage.
|
||||
* @return bytes in use
|
||||
*/
|
||||
size_t hints_get_mem(struct iter_hints* hints);
|
||||
|
||||
/**
|
||||
* Add stub to hints structure. For external use since it recalcs
|
||||
* the tree parents.
|
||||
* @param hints: the hints data structure
|
||||
* @param c: class of zone
|
||||
* @param dp: delegation point with name and target nameservers for new
|
||||
* hints stub. malloced.
|
||||
* @param noprime: set noprime option to true or false on new hint stub.
|
||||
* @return false on failure (out of memory);
|
||||
*/
|
||||
int hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
|
||||
int noprime);
|
||||
|
||||
/**
|
||||
* Remove stub from hints structure. For external use since it
|
||||
* recalcs the tree parents.
|
||||
* @param hints: the hints data structure
|
||||
* @param c: class of stub zone
|
||||
* @param nm: name of stub zone (in uncompressed wireformat).
|
||||
*/
|
||||
void hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm);
|
||||
|
||||
#endif /* ITERATOR_ITER_HINTS_H */
|
263
contrib/unbound/iterator/iter_priv.c
Normal file
263
contrib/unbound/iterator/iter_priv.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* iterator/iter_priv.c - iterative resolver private address and domain store
|
||||
*
|
||||
* Copyright (c) 2008, 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
|
||||
*
|
||||
* This file contains functions to assist the iterator module.
|
||||
* Keep track of the private addresses and lookup fast.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <ldns/dname.h>
|
||||
#include "iterator/iter_priv.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/storage/dnstree.h"
|
||||
|
||||
struct iter_priv* priv_create(void)
|
||||
{
|
||||
struct iter_priv* priv = (struct iter_priv*)calloc(1, sizeof(*priv));
|
||||
if(!priv)
|
||||
return NULL;
|
||||
priv->region = regional_create();
|
||||
if(!priv->region) {
|
||||
priv_delete(priv);
|
||||
return NULL;
|
||||
}
|
||||
addr_tree_init(&priv->a);
|
||||
name_tree_init(&priv->n);
|
||||
return priv;
|
||||
}
|
||||
|
||||
void priv_delete(struct iter_priv* priv)
|
||||
{
|
||||
if(!priv) return;
|
||||
regional_destroy(priv->region);
|
||||
free(priv);
|
||||
}
|
||||
|
||||
/** Read private-addr declarations from config */
|
||||
static int read_addrs(struct iter_priv* priv, struct config_file* cfg)
|
||||
{
|
||||
/* parse addresses, report errors, insert into tree */
|
||||
struct config_strlist* p;
|
||||
struct addr_tree_node* n;
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
socklen_t addrlen;
|
||||
|
||||
for(p = cfg->private_address; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
if(!netblockstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr,
|
||||
&addrlen, &net)) {
|
||||
log_err("cannot parse private-address: %s", p->str);
|
||||
return 0;
|
||||
}
|
||||
n = (struct addr_tree_node*)regional_alloc(priv->region,
|
||||
sizeof(*n));
|
||||
if(!n) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
if(!addr_tree_insert(&priv->a, n, &addr, addrlen, net)) {
|
||||
verbose(VERB_QUERY, "ignoring duplicate "
|
||||
"private-address: %s", p->str);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Read private-domain declarations from config */
|
||||
static int read_names(struct iter_priv* priv, struct config_file* cfg)
|
||||
{
|
||||
/* parse names, report errors, insert into tree */
|
||||
struct config_strlist* p;
|
||||
struct name_tree_node* n;
|
||||
uint8_t* nm;
|
||||
size_t nm_len;
|
||||
int nm_labs;
|
||||
ldns_rdf* rdf;
|
||||
|
||||
for(p = cfg->private_domain; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
rdf = ldns_dname_new_frm_str(p->str);
|
||||
if(!rdf) {
|
||||
log_err("cannot parse private-domain: %s", p->str);
|
||||
return 0;
|
||||
}
|
||||
nm = ldns_rdf_data(rdf);
|
||||
nm_labs = dname_count_size_labels(nm, &nm_len);
|
||||
nm = (uint8_t*)regional_alloc_init(priv->region, nm, nm_len);
|
||||
ldns_rdf_deep_free(rdf);
|
||||
if(!nm) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
n = (struct name_tree_node*)regional_alloc(priv->region,
|
||||
sizeof(*n));
|
||||
if(!n) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
if(!name_tree_insert(&priv->n, n, nm, nm_len, nm_labs,
|
||||
LDNS_RR_CLASS_IN)) {
|
||||
verbose(VERB_QUERY, "ignoring duplicate "
|
||||
"private-domain: %s", p->str);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg)
|
||||
{
|
||||
/* empty the current contents */
|
||||
regional_free_all(priv->region);
|
||||
addr_tree_init(&priv->a);
|
||||
name_tree_init(&priv->n);
|
||||
|
||||
/* read new contents */
|
||||
if(!read_addrs(priv, cfg))
|
||||
return 0;
|
||||
if(!read_names(priv, cfg))
|
||||
return 0;
|
||||
|
||||
/* prepare for lookups */
|
||||
addr_tree_init_parents(&priv->a);
|
||||
name_tree_init_parents(&priv->n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* See if an address is blocked.
|
||||
* @param priv: structure for address storage.
|
||||
* @param addr: address to check
|
||||
* @param addrlen: length of addr.
|
||||
* @return: true if the address must not be queried. false if unlisted.
|
||||
*/
|
||||
static int
|
||||
priv_lookup_addr(struct iter_priv* priv, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
return addr_tree_lookup(&priv->a, addr, addrlen) != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* See if a name is whitelisted.
|
||||
* @param priv: structure for address storage.
|
||||
* @param pkt: the packet (for compression ptrs).
|
||||
* @param name: name to check.
|
||||
* @param name_len: uncompressed length of the name to check.
|
||||
* @param dclass: class to check.
|
||||
* @return: true if the name is OK. false if unlisted.
|
||||
*/
|
||||
static int
|
||||
priv_lookup_name(struct iter_priv* priv, ldns_buffer* pkt,
|
||||
uint8_t* name, size_t name_len, uint16_t dclass)
|
||||
{
|
||||
size_t len;
|
||||
uint8_t decomp[256];
|
||||
int labs;
|
||||
if(name_len >= sizeof(decomp))
|
||||
return 0;
|
||||
dname_pkt_copy(pkt, decomp, name);
|
||||
labs = dname_count_size_labels(decomp, &len);
|
||||
log_assert(name_len == len);
|
||||
return name_tree_lookup(&priv->n, decomp, len, labs, dclass) != NULL;
|
||||
}
|
||||
|
||||
size_t priv_get_mem(struct iter_priv* priv)
|
||||
{
|
||||
if(!priv) return 0;
|
||||
return sizeof(*priv) + regional_get_mem(priv->region);
|
||||
}
|
||||
|
||||
int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
if(priv->a.count == 0)
|
||||
return 0; /* there are no blocked addresses */
|
||||
|
||||
/* see if it is a private name, that is allowed to have any */
|
||||
if(priv_lookup_name(priv, pkt, rrset->dname, rrset->dname_len,
|
||||
ntohs(rrset->rrset_class))) {
|
||||
return 0;
|
||||
} else {
|
||||
/* so its a public name, check the address */
|
||||
socklen_t len;
|
||||
struct rr_parse* rr;
|
||||
if(rrset->type == LDNS_RR_TYPE_A) {
|
||||
struct sockaddr_storage addr;
|
||||
struct sockaddr_in sa;
|
||||
|
||||
len = (socklen_t)sizeof(sa);
|
||||
memset(&sa, 0, len);
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
for(rr = rrset->rr_first; rr; rr = rr->next) {
|
||||
if(ldns_read_uint16(rr->ttl_data+4)
|
||||
!= INET_SIZE)
|
||||
continue;
|
||||
memmove(&sa.sin_addr, rr->ttl_data+4+2,
|
||||
INET_SIZE);
|
||||
memmove(&addr, &sa, len);
|
||||
if(priv_lookup_addr(priv, &addr, len))
|
||||
return 1;
|
||||
}
|
||||
} else if(rrset->type == LDNS_RR_TYPE_AAAA) {
|
||||
struct sockaddr_storage addr;
|
||||
struct sockaddr_in6 sa;
|
||||
len = (socklen_t)sizeof(sa);
|
||||
memset(&sa, 0, len);
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
for(rr = rrset->rr_first; rr; rr = rr->next) {
|
||||
if(ldns_read_uint16(rr->ttl_data+4)
|
||||
!= INET6_SIZE)
|
||||
continue;
|
||||
memmove(&sa.sin6_addr, rr->ttl_data+4+2,
|
||||
INET6_SIZE);
|
||||
memmove(&addr, &sa, len);
|
||||
if(priv_lookup_addr(priv, &addr, len))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
110
contrib/unbound/iterator/iter_priv.h
Normal file
110
contrib/unbound/iterator/iter_priv.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* iterator/iter_priv.h - iterative resolver private address and domain store
|
||||
*
|
||||
* Copyright (c) 2008, 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
|
||||
*
|
||||
* This file contains functions to assist the iterator module.
|
||||
* Keep track of the private addresses and lookup fast.
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_ITER_PRIV_H
|
||||
#define ITERATOR_ITER_PRIV_H
|
||||
#include "util/rbtree.h"
|
||||
#include <ldns/buffer.h>
|
||||
struct iter_env;
|
||||
struct config_file;
|
||||
struct regional;
|
||||
struct rrset_parse;
|
||||
|
||||
/**
|
||||
* Iterator priv structure
|
||||
*/
|
||||
struct iter_priv {
|
||||
/** regional for allocation */
|
||||
struct regional* region;
|
||||
/**
|
||||
* Tree of the address spans that are blocked.
|
||||
* contents of type addr_tree_node.
|
||||
* No further data need, only presence or absence.
|
||||
*/
|
||||
rbtree_t a;
|
||||
/**
|
||||
* Tree of the domains spans that are allowed to contain
|
||||
* the blocked address spans.
|
||||
* contents of type name_tree_node.
|
||||
* No further data need, only presence or absence.
|
||||
*/
|
||||
rbtree_t n;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create priv structure
|
||||
* @return new structure or NULL on error.
|
||||
*/
|
||||
struct iter_priv* priv_create(void);
|
||||
|
||||
/**
|
||||
* Delete priv structure.
|
||||
* @param priv: to delete.
|
||||
*/
|
||||
void priv_delete(struct iter_priv* priv);
|
||||
|
||||
/**
|
||||
* Process priv config.
|
||||
* @param priv: where to store.
|
||||
* @param cfg: config options.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* See if rrset is bad.
|
||||
* @param priv: structure for private address storage.
|
||||
* @param pkt: packet to decompress rrset name in.
|
||||
* @param rrset: the rrset to examine, A or AAAA.
|
||||
* @return true if the rrset is bad and should be removed.
|
||||
*/
|
||||
int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt,
|
||||
struct rrset_parse* rrset);
|
||||
|
||||
/**
|
||||
* Get memory used by priv structure.
|
||||
* @param priv: structure for address storage.
|
||||
* @return bytes in use.
|
||||
*/
|
||||
size_t priv_get_mem(struct iter_priv* priv);
|
||||
|
||||
#endif /* ITERATOR_ITER_PRIV_H */
|
286
contrib/unbound/iterator/iter_resptype.c
Normal file
286
contrib/unbound/iterator/iter_resptype.c
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* iterator/iter_resptype.c - response type information and classification.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file defines the response type. DNS Responses can be classified as
|
||||
* one of the response types.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <ldns/packet.h>
|
||||
#include "iterator/iter_resptype.h"
|
||||
#include "iterator/iter_delegpt.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/dname.h"
|
||||
|
||||
enum response_type
|
||||
response_type_from_cache(struct dns_msg* msg,
|
||||
struct query_info* request)
|
||||
{
|
||||
/* If the message is NXDOMAIN, then it is an ANSWER. */
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN)
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
if(request->qtype == LDNS_RR_TYPE_ANY)
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
|
||||
/* First we look at the answer section. This can tell us if this is
|
||||
* CNAME or positive ANSWER. */
|
||||
if(msg->rep->an_numrrsets > 0) {
|
||||
/* Now look at the answer section first. 3 states:
|
||||
* o our answer is there directly,
|
||||
* o our answer is there after a cname,
|
||||
* o or there is just a cname. */
|
||||
uint8_t* mname = request->qname;
|
||||
size_t mname_len = request->qname_len;
|
||||
size_t i;
|
||||
for(i=0; i<msg->rep->an_numrrsets; i++) {
|
||||
struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
|
||||
|
||||
/* If we have encountered an answer (before or
|
||||
* after a CNAME), then we are done! Note that
|
||||
* if qtype == CNAME then this will be noted as
|
||||
* an ANSWER before it gets treated as a CNAME,
|
||||
* as it should */
|
||||
if(ntohs(s->rk.type) == request->qtype &&
|
||||
ntohs(s->rk.rrset_class) == request->qclass &&
|
||||
query_dname_compare(mname, s->rk.dname) == 0) {
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
|
||||
/* If we have encountered a CNAME, make sure that
|
||||
* it is relevant. */
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
|
||||
query_dname_compare(mname, s->rk.dname) == 0) {
|
||||
get_cname_target(s, &mname, &mname_len);
|
||||
}
|
||||
}
|
||||
|
||||
/* if we encountered a CNAME (or a bunch of CNAMEs), and
|
||||
* still got to here, then it is a CNAME response. (i.e.,
|
||||
* the CNAME chain didn't terminate in an answer rrset.) */
|
||||
if(mname != request->qname) {
|
||||
return RESPONSE_TYPE_CNAME;
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point, since we don't need to detect REFERRAL or LAME
|
||||
* messages, it can only be an ANSWER. */
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
|
||||
enum response_type
|
||||
response_type_from_server(int rdset,
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp)
|
||||
{
|
||||
uint8_t* origzone = (uint8_t*)"\000"; /* the default */
|
||||
struct ub_packed_rrset_key* s;
|
||||
size_t i;
|
||||
|
||||
if(!msg || !request)
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
|
||||
/* If the message is NXDOMAIN, then it answers the question. */
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) {
|
||||
/* make sure its not recursive when we don't want it to */
|
||||
if( (msg->rep->flags&BIT_RA) &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_REC_LAME;
|
||||
/* it could be a CNAME with NXDOMAIN rcode */
|
||||
for(i=0; i<msg->rep->an_numrrsets; i++) {
|
||||
s = msg->rep->rrsets[i];
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
|
||||
query_dname_compare(request->qname,
|
||||
s->rk.dname) == 0) {
|
||||
return RESPONSE_TYPE_CNAME;
|
||||
}
|
||||
}
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
|
||||
/* Other response codes mean (so far) to throw the response away as
|
||||
* meaningless and move on to the next nameserver. */
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) != LDNS_RCODE_NOERROR)
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
|
||||
/* Note: TC bit has already been handled */
|
||||
|
||||
if(dp) {
|
||||
origzone = dp->name;
|
||||
}
|
||||
|
||||
/* First we look at the answer section. This can tell us if this is a
|
||||
* CNAME or ANSWER or (provisional) ANSWER. */
|
||||
if(msg->rep->an_numrrsets > 0) {
|
||||
uint8_t* mname = request->qname;
|
||||
size_t mname_len = request->qname_len;
|
||||
|
||||
/* Now look at the answer section first. 3 states: our
|
||||
* answer is there directly, our answer is there after
|
||||
* a cname, or there is just a cname. */
|
||||
for(i=0; i<msg->rep->an_numrrsets; i++) {
|
||||
s = msg->rep->rrsets[i];
|
||||
|
||||
/* if the answer section has NS rrset, and qtype ANY
|
||||
* and the delegation is lower, and no CNAMEs followed,
|
||||
* this is a referral where the NS went to AN section */
|
||||
if((request->qtype == LDNS_RR_TYPE_ANY ||
|
||||
request->qtype == LDNS_RR_TYPE_NS) &&
|
||||
ntohs(s->rk.type) == LDNS_RR_TYPE_NS &&
|
||||
ntohs(s->rk.rrset_class) == request->qclass &&
|
||||
dname_strict_subdomain_c(s->rk.dname,
|
||||
origzone)) {
|
||||
if((msg->rep->flags&BIT_AA))
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
return RESPONSE_TYPE_REFERRAL;
|
||||
}
|
||||
|
||||
/* If we have encountered an answer (before or
|
||||
* after a CNAME), then we are done! Note that
|
||||
* if qtype == CNAME then this will be noted as an
|
||||
* ANSWER before it gets treated as a CNAME, as
|
||||
* it should. */
|
||||
if(ntohs(s->rk.type) == request->qtype &&
|
||||
ntohs(s->rk.rrset_class) == request->qclass &&
|
||||
query_dname_compare(mname, s->rk.dname) == 0) {
|
||||
if((msg->rep->flags&BIT_AA))
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
/* If the AA bit isn't on, and we've seen
|
||||
* the answer, we only provisionally say
|
||||
* 'ANSWER' -- it very well could be a
|
||||
* REFERRAL. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we have encountered a CNAME, make sure that
|
||||
* it is relevant. */
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
|
||||
query_dname_compare(mname, s->rk.dname) == 0) {
|
||||
get_cname_target(s, &mname, &mname_len);
|
||||
}
|
||||
}
|
||||
/* not a referral, and qtype any, thus an answer */
|
||||
if(request->qtype == LDNS_RR_TYPE_ANY)
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
/* if we encountered a CNAME (or a bunch of CNAMEs), and
|
||||
* still got to here, then it is a CNAME response.
|
||||
* (This is regardless of the AA bit at this point) */
|
||||
if(mname != request->qname) {
|
||||
return RESPONSE_TYPE_CNAME;
|
||||
}
|
||||
}
|
||||
|
||||
/* Looking at the authority section, we just look and see if
|
||||
* there is a SOA record, that means a NOERROR/NODATA */
|
||||
for(i = msg->rep->an_numrrsets; i < (msg->rep->an_numrrsets +
|
||||
msg->rep->ns_numrrsets); i++) {
|
||||
s = msg->rep->rrsets[i];
|
||||
|
||||
/* The normal way of detecting NOERROR/NODATA. */
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA &&
|
||||
dname_subdomain_c(request->qname, s->rk.dname)) {
|
||||
/* we do our own recursion, thank you */
|
||||
if( (msg->rep->flags&BIT_RA) &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_REC_LAME;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
}
|
||||
/* Looking at the authority section, we just look and see if
|
||||
* there is a delegation NS set, turning it into a delegation.
|
||||
* Otherwise, we will have to conclude ANSWER (either it is
|
||||
* NOERROR/NODATA, or an non-authoritative answer). */
|
||||
for(i = msg->rep->an_numrrsets; i < (msg->rep->an_numrrsets +
|
||||
msg->rep->ns_numrrsets); i++) {
|
||||
s = msg->rep->rrsets[i];
|
||||
|
||||
/* Detect REFERRAL/LAME/ANSWER based on the relationship
|
||||
* of the NS set to the originating zone name. */
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_NS) {
|
||||
/* If we are getting an NS set for the zone we
|
||||
* thought we were contacting, then it is an answer.*/
|
||||
if(query_dname_compare(s->rk.dname, origzone) == 0) {
|
||||
/* see if mistakenly a recursive server was
|
||||
* deployed and is responding nonAA */
|
||||
if( (msg->rep->flags&BIT_RA) &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_REC_LAME;
|
||||
/* Or if a lame server is deployed,
|
||||
* which gives ns==zone delegation from cache
|
||||
* without AA bit as well, with nodata nosoa*/
|
||||
/* real answer must be +AA and SOA RFC(2308),
|
||||
* so this is wrong, and we SERVFAIL it if
|
||||
* this is the only possible reply, if it
|
||||
* is misdeployed the THROWAWAY makes us pick
|
||||
* the next server from the selection */
|
||||
if(msg->rep->an_numrrsets==0 &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
/* If we are getting a referral upwards (or to
|
||||
* the same zone), then the server is 'lame'. */
|
||||
if(dname_subdomain_c(origzone, s->rk.dname)) {
|
||||
if(rdset) /* forward or reclame not LAME */
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
return RESPONSE_TYPE_LAME;
|
||||
}
|
||||
/* If the NS set is below the delegation point we
|
||||
* are on, and it is non-authoritative, then it is
|
||||
* a referral, otherwise it is an answer. */
|
||||
if(dname_subdomain_c(s->rk.dname, origzone)) {
|
||||
/* NOTE: I no longer remember in what case
|
||||
* we would like this to be an answer.
|
||||
* NODATA should have a SOA or nothing,
|
||||
* not an NS rrset.
|
||||
* True, referrals should not have the AA
|
||||
* bit set, but... */
|
||||
|
||||
/* if((msg->rep->flags&BIT_AA))
|
||||
return RESPONSE_TYPE_ANSWER; */
|
||||
return RESPONSE_TYPE_REFERRAL;
|
||||
}
|
||||
/* Otherwise, the NS set is irrelevant. */
|
||||
}
|
||||
}
|
||||
|
||||
/* If we've gotten this far, this is NOERROR/NODATA (which could
|
||||
* be an entirely empty message) */
|
||||
/* check if recursive answer; saying it has empty cache */
|
||||
if( (msg->rep->flags&BIT_RA) && !(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_REC_LAME;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
127
contrib/unbound/iterator/iter_resptype.h
Normal file
127
contrib/unbound/iterator/iter_resptype.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* iterator/iter_resptype.h - response type information and classification.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file defines the response type. DNS Responses can be classified as
|
||||
* one of the response types.
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_ITER_RESPTYPE_H
|
||||
#define ITERATOR_ITER_RESPTYPE_H
|
||||
struct dns_msg;
|
||||
struct query_info;
|
||||
struct delegpt;
|
||||
|
||||
/**
|
||||
* The response type is used to interpret the response.
|
||||
*/
|
||||
enum response_type {
|
||||
/**
|
||||
* 'untyped' means that the type of this response hasn't been
|
||||
* assigned.
|
||||
*/
|
||||
RESPONSE_TYPE_UNTYPED = 0,
|
||||
|
||||
/**
|
||||
* 'answer' means that the response terminates the resolution
|
||||
* process.
|
||||
*/
|
||||
RESPONSE_TYPE_ANSWER,
|
||||
|
||||
/** 'delegation' means that the response is a delegation. */
|
||||
RESPONSE_TYPE_REFERRAL,
|
||||
|
||||
/**
|
||||
* 'cname' means that the response is a cname without the final
|
||||
* answer, and thus must be restarted.
|
||||
*/
|
||||
RESPONSE_TYPE_CNAME,
|
||||
|
||||
/**
|
||||
* 'throwaway' means that this particular response should be
|
||||
* discarded and the next nameserver should be contacted
|
||||
*/
|
||||
RESPONSE_TYPE_THROWAWAY,
|
||||
|
||||
/**
|
||||
* 'lame' means that this particular response indicates that
|
||||
* the nameserver knew nothing about the question.
|
||||
*/
|
||||
RESPONSE_TYPE_LAME,
|
||||
|
||||
/**
|
||||
* Recursion lame means that the nameserver is some sort of
|
||||
* open recursor, and not authoritative for the question.
|
||||
* It may know something, but not authoritatively.
|
||||
*/
|
||||
RESPONSE_TYPE_REC_LAME
|
||||
};
|
||||
|
||||
/**
|
||||
* Classifies a response message from cache based on the current request.
|
||||
* Note that this routine assumes that THROWAWAY or LAME responses will not
|
||||
* occur. Also, it will not detect REFERRAL type messages, since those are
|
||||
* (currently) automatically classified based on how they came from the
|
||||
* cache (findDelegation() instead of lookup()).
|
||||
*
|
||||
* @param msg: the message from the cache.
|
||||
* @param request: the request that generated the response.
|
||||
* @return the response type (CNAME or ANSWER).
|
||||
*/
|
||||
enum response_type response_type_from_cache(struct dns_msg* msg,
|
||||
struct query_info* request);
|
||||
|
||||
/**
|
||||
* Classifies a response message (from the wire) based on the current
|
||||
* request.
|
||||
*
|
||||
* NOTE: currently this routine uses the AA bit in the response to help
|
||||
* distinguish between some non-standard referrals and answers. It also
|
||||
* relies somewhat on the originating zone to be accurate (for lameness
|
||||
* detection, mostly).
|
||||
*
|
||||
* @param rdset: if RD bit was sent in query sent by unbound.
|
||||
* @param msg: the message from the cache.
|
||||
* @param request: the request that generated the response.
|
||||
* @param dp: The delegation point that was being queried
|
||||
* when the response was returned.
|
||||
* @return the response type (CNAME or ANSWER).
|
||||
*/
|
||||
enum response_type response_type_from_server(int rdset,
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp);
|
||||
|
||||
#endif /* ITERATOR_ITER_RESPTYPE_H */
|
751
contrib/unbound/iterator/iter_scrub.c
Normal file
751
contrib/unbound/iterator/iter_scrub.c
Normal file
@ -0,0 +1,751 @@
|
||||
/*
|
||||
* iterator/iter_scrub.c - scrubbing, normalization, sanitization of DNS msgs.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file has routine(s) for cleaning up incoming DNS messages from
|
||||
* possible useless or malicious junk in it.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "iterator/iter_scrub.h"
|
||||
#include "iterator/iterator.h"
|
||||
#include "iterator/iter_priv.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/module.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/alloc.h"
|
||||
|
||||
/** RRset flag used during scrubbing. The RRset is OK. */
|
||||
#define RRSET_SCRUB_OK 0x80
|
||||
|
||||
/** remove rrset, update loop variables */
|
||||
static void
|
||||
remove_rrset(const char* str, ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct rrset_parse* prev, struct rrset_parse** rrset)
|
||||
{
|
||||
if(verbosity >= VERB_QUERY
|
||||
&& (*rrset)->dname_len <= LDNS_MAX_DOMAINLEN) {
|
||||
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
|
||||
dname_pkt_copy(pkt, buf, (*rrset)->dname);
|
||||
log_nametypeclass(VERB_QUERY, str, buf,
|
||||
(*rrset)->type, ntohs((*rrset)->rrset_class));
|
||||
}
|
||||
if(prev)
|
||||
prev->rrset_all_next = (*rrset)->rrset_all_next;
|
||||
else msg->rrset_first = (*rrset)->rrset_all_next;
|
||||
if(msg->rrset_last == *rrset)
|
||||
msg->rrset_last = prev;
|
||||
msg->rrset_count --;
|
||||
switch((*rrset)->section) {
|
||||
case LDNS_SECTION_ANSWER: msg->an_rrsets--; break;
|
||||
case LDNS_SECTION_AUTHORITY: msg->ns_rrsets--; break;
|
||||
case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets--; break;
|
||||
default: log_assert(0);
|
||||
}
|
||||
msgparse_bucket_remove(msg, *rrset);
|
||||
*rrset = (*rrset)->rrset_all_next;
|
||||
}
|
||||
|
||||
/** return true if rr type has additional names in it */
|
||||
static int
|
||||
has_additional(uint16_t t)
|
||||
{
|
||||
switch(t) {
|
||||
case LDNS_RR_TYPE_MB:
|
||||
case LDNS_RR_TYPE_MD:
|
||||
case LDNS_RR_TYPE_MF:
|
||||
case LDNS_RR_TYPE_NS:
|
||||
case LDNS_RR_TYPE_MX:
|
||||
case LDNS_RR_TYPE_KX:
|
||||
case LDNS_RR_TYPE_SRV:
|
||||
return 1;
|
||||
case LDNS_RR_TYPE_NAPTR:
|
||||
/* TODO: NAPTR not supported, glue stripped off */
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** get additional name from rrset RR, return false if no name present */
|
||||
static int
|
||||
get_additional_name(struct rrset_parse* rrset, struct rr_parse* rr,
|
||||
uint8_t** nm, size_t* nmlen, ldns_buffer* pkt)
|
||||
{
|
||||
size_t offset = 0;
|
||||
size_t len, oldpos;
|
||||
switch(rrset->type) {
|
||||
case LDNS_RR_TYPE_MB:
|
||||
case LDNS_RR_TYPE_MD:
|
||||
case LDNS_RR_TYPE_MF:
|
||||
case LDNS_RR_TYPE_NS:
|
||||
offset = 0;
|
||||
break;
|
||||
case LDNS_RR_TYPE_MX:
|
||||
case LDNS_RR_TYPE_KX:
|
||||
offset = 2;
|
||||
break;
|
||||
case LDNS_RR_TYPE_SRV:
|
||||
offset = 6;
|
||||
break;
|
||||
case LDNS_RR_TYPE_NAPTR:
|
||||
/* TODO: NAPTR not supported, glue stripped off */
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
len = ldns_read_uint16(rr->ttl_data+sizeof(uint32_t));
|
||||
if(len < offset+1)
|
||||
return 0; /* rdata field too small */
|
||||
*nm = rr->ttl_data+sizeof(uint32_t)+sizeof(uint16_t)+offset;
|
||||
oldpos = ldns_buffer_position(pkt);
|
||||
ldns_buffer_set_position(pkt, (size_t)(*nm - ldns_buffer_begin(pkt)));
|
||||
*nmlen = pkt_dname_len(pkt);
|
||||
ldns_buffer_set_position(pkt, oldpos);
|
||||
if(*nmlen == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Place mark on rrsets in additional section they are OK */
|
||||
static void
|
||||
mark_additional_rrset(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
/* Mark A and AAAA for NS as appropriate additional section info. */
|
||||
uint8_t* nm = NULL;
|
||||
size_t nmlen = 0;
|
||||
struct rr_parse* rr;
|
||||
|
||||
if(!has_additional(rrset->type))
|
||||
return;
|
||||
for(rr = rrset->rr_first; rr; rr = rr->next) {
|
||||
if(get_additional_name(rrset, rr, &nm, &nmlen, pkt)) {
|
||||
/* mark A */
|
||||
hashvalue_t h = pkt_hash_rrset(pkt, nm, LDNS_RR_TYPE_A,
|
||||
rrset->rrset_class, 0);
|
||||
struct rrset_parse* r = msgparse_hashtable_lookup(
|
||||
msg, pkt, h, 0, nm, nmlen,
|
||||
LDNS_RR_TYPE_A, rrset->rrset_class);
|
||||
if(r && r->section == LDNS_SECTION_ADDITIONAL) {
|
||||
r->flags |= RRSET_SCRUB_OK;
|
||||
}
|
||||
|
||||
/* mark AAAA */
|
||||
h = pkt_hash_rrset(pkt, nm, LDNS_RR_TYPE_AAAA,
|
||||
rrset->rrset_class, 0);
|
||||
r = msgparse_hashtable_lookup(msg, pkt, h, 0, nm,
|
||||
nmlen, LDNS_RR_TYPE_AAAA, rrset->rrset_class);
|
||||
if(r && r->section == LDNS_SECTION_ADDITIONAL) {
|
||||
r->flags |= RRSET_SCRUB_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Get target name of a CNAME */
|
||||
static int
|
||||
parse_get_cname_target(struct rrset_parse* rrset, uint8_t** sname,
|
||||
size_t* snamelen)
|
||||
{
|
||||
if(rrset->rr_count != 1) {
|
||||
struct rr_parse* sig;
|
||||
verbose(VERB_ALGO, "Found CNAME rrset with "
|
||||
"size > 1: %u", (unsigned)rrset->rr_count);
|
||||
/* use the first CNAME! */
|
||||
rrset->rr_count = 1;
|
||||
rrset->size = rrset->rr_first->size;
|
||||
for(sig=rrset->rrsig_first; sig; sig=sig->next)
|
||||
rrset->size += sig->size;
|
||||
rrset->rr_last = rrset->rr_first;
|
||||
rrset->rr_first->next = NULL;
|
||||
}
|
||||
if(rrset->rr_first->size < sizeof(uint16_t)+1)
|
||||
return 0; /* CNAME rdata too small */
|
||||
*sname = rrset->rr_first->ttl_data + sizeof(uint32_t)
|
||||
+ sizeof(uint16_t); /* skip ttl, rdatalen */
|
||||
*snamelen = rrset->rr_first->size - sizeof(uint16_t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Synthesize CNAME from DNAME, false if too long */
|
||||
static int
|
||||
synth_cname(uint8_t* qname, size_t qnamelen, struct rrset_parse* dname_rrset,
|
||||
uint8_t* alias, size_t* aliaslen, ldns_buffer* pkt)
|
||||
{
|
||||
/* we already know that sname is a strict subdomain of DNAME owner */
|
||||
uint8_t* dtarg = NULL;
|
||||
size_t dtarglen;
|
||||
if(!parse_get_cname_target(dname_rrset, &dtarg, &dtarglen))
|
||||
return 0;
|
||||
log_assert(qnamelen > dname_rrset->dname_len);
|
||||
/* DNAME from com. to net. with qname example.com. -> example.net. */
|
||||
/* so: \3com\0 to \3net\0 and qname \7example\3com\0 */
|
||||
*aliaslen = qnamelen + dtarglen - dname_rrset->dname_len;
|
||||
if(*aliaslen > LDNS_MAX_DOMAINLEN)
|
||||
return 0; /* should have been RCODE YXDOMAIN */
|
||||
/* decompress dnames into buffer, we know it fits */
|
||||
dname_pkt_copy(pkt, alias, qname);
|
||||
dname_pkt_copy(pkt, alias+(qnamelen-dname_rrset->dname_len), dtarg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** synthesize a CNAME rrset */
|
||||
static struct rrset_parse*
|
||||
synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
size_t aliaslen, struct regional* region, struct msg_parse* msg,
|
||||
struct rrset_parse* rrset, struct rrset_parse* prev,
|
||||
struct rrset_parse* nx, ldns_buffer* pkt)
|
||||
{
|
||||
struct rrset_parse* cn = (struct rrset_parse*)regional_alloc(region,
|
||||
sizeof(struct rrset_parse));
|
||||
if(!cn)
|
||||
return NULL;
|
||||
memset(cn, 0, sizeof(*cn));
|
||||
cn->rr_first = (struct rr_parse*)regional_alloc(region,
|
||||
sizeof(struct rr_parse));
|
||||
if(!cn->rr_first)
|
||||
return NULL;
|
||||
cn->rr_last = cn->rr_first;
|
||||
/* CNAME from sname to alias */
|
||||
cn->dname = (uint8_t*)regional_alloc(region, *snamelen);
|
||||
if(!cn->dname)
|
||||
return NULL;
|
||||
dname_pkt_copy(pkt, cn->dname, *sname);
|
||||
cn->dname_len = *snamelen;
|
||||
cn->type = LDNS_RR_TYPE_CNAME;
|
||||
cn->section = rrset->section;
|
||||
cn->rrset_class = rrset->rrset_class;
|
||||
cn->rr_count = 1;
|
||||
cn->size = sizeof(uint16_t) + aliaslen;
|
||||
cn->hash=pkt_hash_rrset(pkt, cn->dname, cn->type, cn->rrset_class, 0);
|
||||
/* allocate TTL + rdatalen + uncompressed dname */
|
||||
memset(cn->rr_first, 0, sizeof(struct rr_parse));
|
||||
cn->rr_first->outside_packet = 1;
|
||||
cn->rr_first->ttl_data = (uint8_t*)regional_alloc(region,
|
||||
sizeof(uint32_t)+sizeof(uint16_t)+aliaslen);
|
||||
if(!cn->rr_first->ttl_data)
|
||||
return NULL;
|
||||
ldns_write_uint32(cn->rr_first->ttl_data, 0); /* TTL = 0 */
|
||||
ldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen);
|
||||
memmove(cn->rr_first->ttl_data+6, alias, aliaslen);
|
||||
cn->rr_first->size = sizeof(uint16_t)+aliaslen;
|
||||
|
||||
/* link it in */
|
||||
cn->rrset_all_next = nx;
|
||||
if(prev)
|
||||
prev->rrset_all_next = cn;
|
||||
else msg->rrset_first = cn;
|
||||
if(nx == NULL)
|
||||
msg->rrset_last = cn;
|
||||
msg->rrset_count ++;
|
||||
msg->an_rrsets++;
|
||||
/* it is not inserted in the msg hashtable. */
|
||||
|
||||
*sname = cn->rr_first->ttl_data + sizeof(uint32_t)+sizeof(uint16_t);
|
||||
*snamelen = aliaslen;
|
||||
return cn;
|
||||
}
|
||||
|
||||
/** check if DNAME applies to a name */
|
||||
static int
|
||||
pkt_strict_sub(ldns_buffer* pkt, uint8_t* sname, uint8_t* dr)
|
||||
{
|
||||
uint8_t buf1[LDNS_MAX_DOMAINLEN+1];
|
||||
uint8_t buf2[LDNS_MAX_DOMAINLEN+1];
|
||||
/* decompress names */
|
||||
dname_pkt_copy(pkt, buf1, sname);
|
||||
dname_pkt_copy(pkt, buf2, dr);
|
||||
return dname_strict_subdomain_c(buf1, buf2);
|
||||
}
|
||||
|
||||
/** check subdomain with decompression */
|
||||
static int
|
||||
pkt_sub(ldns_buffer* pkt, uint8_t* comprname, uint8_t* zone)
|
||||
{
|
||||
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
|
||||
dname_pkt_copy(pkt, buf, comprname);
|
||||
return dname_subdomain_c(buf, zone);
|
||||
}
|
||||
|
||||
/** check subdomain with decompression, compressed is parent */
|
||||
static int
|
||||
sub_of_pkt(ldns_buffer* pkt, uint8_t* zone, uint8_t* comprname)
|
||||
{
|
||||
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
|
||||
dname_pkt_copy(pkt, buf, comprname);
|
||||
return dname_subdomain_c(zone, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine normalizes a response. This includes removing "irrelevant"
|
||||
* records from the answer and additional sections and (re)synthesizing
|
||||
* CNAMEs from DNAMEs, if present.
|
||||
*
|
||||
* @param pkt: packet.
|
||||
* @param msg: msg to normalize.
|
||||
* @param qinfo: original query.
|
||||
* @param region: where to allocate synthesized CNAMEs.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
static int
|
||||
scrub_normalize(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, struct regional* region)
|
||||
{
|
||||
uint8_t* sname = qinfo->qname;
|
||||
size_t snamelen = qinfo->qname_len;
|
||||
struct rrset_parse* rrset, *prev, *nsset=NULL;
|
||||
|
||||
if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR &&
|
||||
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN)
|
||||
return 1;
|
||||
|
||||
/* For the ANSWER section, remove all "irrelevant" records and add
|
||||
* synthesized CNAMEs from DNAMEs
|
||||
* This will strip out-of-order CNAMEs as well. */
|
||||
|
||||
/* walk through the parse packet rrset list, keep track of previous
|
||||
* for insert and delete ease, and examine every RRset */
|
||||
prev = NULL;
|
||||
rrset = msg->rrset_first;
|
||||
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
|
||||
if(rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
pkt_strict_sub(pkt, sname, rrset->dname)) {
|
||||
/* check if next rrset is correct CNAME. else,
|
||||
* synthesize a CNAME */
|
||||
struct rrset_parse* nx = rrset->rrset_all_next;
|
||||
uint8_t alias[LDNS_MAX_DOMAINLEN+1];
|
||||
size_t aliaslen = 0;
|
||||
if(rrset->rr_count != 1) {
|
||||
verbose(VERB_ALGO, "Found DNAME rrset with "
|
||||
"size > 1: %u",
|
||||
(unsigned)rrset->rr_count);
|
||||
return 0;
|
||||
}
|
||||
if(!synth_cname(sname, snamelen, rrset, alias,
|
||||
&aliaslen, pkt)) {
|
||||
verbose(VERB_ALGO, "synthesized CNAME "
|
||||
"too long");
|
||||
return 0;
|
||||
}
|
||||
if(nx && nx->type == LDNS_RR_TYPE_CNAME &&
|
||||
dname_pkt_compare(pkt, sname, nx->dname) == 0) {
|
||||
/* check next cname */
|
||||
uint8_t* t = NULL;
|
||||
size_t tlen = 0;
|
||||
if(!parse_get_cname_target(rrset, &t, &tlen))
|
||||
return 0;
|
||||
if(dname_pkt_compare(pkt, alias, t) == 0) {
|
||||
/* it's OK and better capitalized */
|
||||
prev = rrset;
|
||||
rrset = nx;
|
||||
continue;
|
||||
}
|
||||
/* synth ourselves */
|
||||
}
|
||||
/* synth a CNAME rrset */
|
||||
prev = synth_cname_rrset(&sname, &snamelen, alias,
|
||||
aliaslen, region, msg, rrset, rrset, nx, pkt);
|
||||
if(!prev) {
|
||||
log_err("out of memory synthesizing CNAME");
|
||||
return 0;
|
||||
}
|
||||
/* FIXME: resolve the conflict between synthesized
|
||||
* CNAME ttls and the cache. */
|
||||
rrset = nx;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
/* The only records in the ANSWER section not allowed to */
|
||||
if(dname_pkt_compare(pkt, sname, rrset->dname) != 0) {
|
||||
remove_rrset("normalize: removing irrelevant RRset:",
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Follow the CNAME chain. */
|
||||
if(rrset->type == LDNS_RR_TYPE_CNAME) {
|
||||
uint8_t* oldsname = sname;
|
||||
if(!parse_get_cname_target(rrset, &sname, &snamelen))
|
||||
return 0;
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
/* in CNAME ANY response, can have data after CNAME */
|
||||
if(qinfo->qtype == LDNS_RR_TYPE_ANY) {
|
||||
while(rrset && rrset->section ==
|
||||
LDNS_SECTION_ANSWER &&
|
||||
dname_pkt_compare(pkt, oldsname,
|
||||
rrset->dname) == 0) {
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Otherwise, make sure that the RRset matches the qtype. */
|
||||
if(qinfo->qtype != LDNS_RR_TYPE_ANY &&
|
||||
qinfo->qtype != rrset->type) {
|
||||
remove_rrset("normalize: removing irrelevant RRset:",
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Mark the additional names from relevant rrset as OK. */
|
||||
/* only for RRsets that match the query name, other ones
|
||||
* will be removed by sanitize, so no additional for them */
|
||||
if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) == 0)
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
|
||||
/* Mark additional names from AUTHORITY */
|
||||
while(rrset && rrset->section == LDNS_SECTION_AUTHORITY) {
|
||||
if(rrset->type==LDNS_RR_TYPE_DNAME ||
|
||||
rrset->type==LDNS_RR_TYPE_CNAME ||
|
||||
rrset->type==LDNS_RR_TYPE_A ||
|
||||
rrset->type==LDNS_RR_TYPE_AAAA) {
|
||||
remove_rrset("normalize: removing irrelevant "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
/* only one NS set allowed in authority section */
|
||||
if(rrset->type==LDNS_RR_TYPE_NS) {
|
||||
/* NS set must be pertinent to the query */
|
||||
if(!sub_of_pkt(pkt, qinfo->qname, rrset->dname)) {
|
||||
remove_rrset("normalize: removing irrelevant "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(nsset == NULL) {
|
||||
nsset = rrset;
|
||||
} else {
|
||||
remove_rrset("normalize: removing irrelevant "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
|
||||
/* For each record in the additional section, remove it if it is an
|
||||
* address record and not in the collection of additional names
|
||||
* found in ANSWER and AUTHORITY. */
|
||||
/* These records have not been marked OK previously */
|
||||
while(rrset && rrset->section == LDNS_SECTION_ADDITIONAL) {
|
||||
/* FIXME: what about other types? */
|
||||
if(rrset->type==LDNS_RR_TYPE_A ||
|
||||
rrset->type==LDNS_RR_TYPE_AAAA)
|
||||
{
|
||||
if((rrset->flags & RRSET_SCRUB_OK)) {
|
||||
/* remove flag to clean up flags variable */
|
||||
rrset->flags &= ~RRSET_SCRUB_OK;
|
||||
} else {
|
||||
remove_rrset("normalize: removing irrelevant "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(rrset->type==LDNS_RR_TYPE_DNAME ||
|
||||
rrset->type==LDNS_RR_TYPE_CNAME ||
|
||||
rrset->type==LDNS_RR_TYPE_NS) {
|
||||
remove_rrset("normalize: removing irrelevant "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store potential poison in the cache (only if hardening disabled).
|
||||
* The rrset is stored in the cache but removed from the message.
|
||||
* So that it will be used for infrastructure purposes, but not be
|
||||
* returned to the client.
|
||||
* @param pkt: packet
|
||||
* @param msg: message parsed
|
||||
* @param env: environment with cache
|
||||
* @param rrset: to store.
|
||||
*/
|
||||
static void
|
||||
store_rrset(ldns_buffer* pkt, struct msg_parse* msg, struct module_env* env,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
struct ub_packed_rrset_key* k;
|
||||
struct packed_rrset_data* d;
|
||||
struct rrset_ref ref;
|
||||
uint32_t now = *env->now;
|
||||
|
||||
k = alloc_special_obtain(env->alloc);
|
||||
if(!k)
|
||||
return;
|
||||
k->entry.data = NULL;
|
||||
if(!parse_copy_decompress_rrset(pkt, msg, rrset, NULL, k)) {
|
||||
alloc_special_release(env->alloc, k);
|
||||
return;
|
||||
}
|
||||
d = (struct packed_rrset_data*)k->entry.data;
|
||||
packed_rrset_ttl_add(d, now);
|
||||
ref.key = k;
|
||||
ref.id = k->id;
|
||||
/*ignore ret: it was in the cache, ref updated */
|
||||
(void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, now);
|
||||
}
|
||||
|
||||
/** Check if there are SOA records in the authority section (negative) */
|
||||
static int
|
||||
soa_in_auth(struct msg_parse* msg)
|
||||
{
|
||||
struct rrset_parse* rrset;
|
||||
for(rrset = msg->rrset_first; rrset; rrset = rrset->rrset_all_next)
|
||||
if(rrset->type == LDNS_RR_TYPE_SOA &&
|
||||
rrset->section == LDNS_SECTION_AUTHORITY)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if right hand name in NSEC is within zone
|
||||
* @param rrset: the NSEC rrset
|
||||
* @param zonename: the zone name.
|
||||
* @return true if BAD.
|
||||
*/
|
||||
static int sanitize_nsec_is_overreach(struct rrset_parse* rrset,
|
||||
uint8_t* zonename)
|
||||
{
|
||||
struct rr_parse* rr;
|
||||
uint8_t* rhs;
|
||||
size_t len;
|
||||
log_assert(rrset->type == LDNS_RR_TYPE_NSEC);
|
||||
for(rr = rrset->rr_first; rr; rr = rr->next) {
|
||||
rhs = rr->ttl_data+4+2;
|
||||
len = ldns_read_uint16(rr->ttl_data+4);
|
||||
if(!dname_valid(rhs, len)) {
|
||||
/* malformed domain name in rdata */
|
||||
return 1;
|
||||
}
|
||||
if(!dname_subdomain_c(rhs, zonename)) {
|
||||
/* overreaching */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* all NSEC RRs OK */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a response event, remove suspect RRsets from the response.
|
||||
* "Suspect" rrsets are potentially poison. Note that this routine expects
|
||||
* the response to be in a "normalized" state -- that is, all "irrelevant"
|
||||
* RRsets have already been removed, CNAMEs are in order, etc.
|
||||
*
|
||||
* @param pkt: packet.
|
||||
* @param msg: msg to normalize.
|
||||
* @param qinfo: the question originally asked.
|
||||
* @param zonename: name of server zone.
|
||||
* @param env: module environment with config and cache.
|
||||
* @param ie: iterator environment with private address data.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
static int
|
||||
scrub_sanitize(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct module_env* env,
|
||||
struct iter_env* ie)
|
||||
{
|
||||
int del_addi = 0; /* if additional-holding rrsets are deleted, we
|
||||
do not trust the normalized additional-A-AAAA any more */
|
||||
struct rrset_parse* rrset, *prev;
|
||||
prev = NULL;
|
||||
rrset = msg->rrset_first;
|
||||
|
||||
/* the first DNAME is allowed to stay. It needs checking before
|
||||
* it can be used from the cache. After normalization, an initial
|
||||
* DNAME will have a correctly synthesized CNAME after it. */
|
||||
if(rrset && rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
rrset->section == LDNS_SECTION_ANSWER &&
|
||||
pkt_strict_sub(pkt, qinfo->qname, rrset->dname) &&
|
||||
pkt_sub(pkt, rrset->dname, zonename)) {
|
||||
prev = rrset; /* DNAME allowed to stay in answer section */
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
|
||||
/* remove all records from the answer section that are
|
||||
* not the same domain name as the query domain name.
|
||||
* The answer section should contain rrsets with the same name
|
||||
* as the question. For DNAMEs a CNAME has been synthesized.
|
||||
* Wildcards have the query name in answer section.
|
||||
* ANY queries get query name in answer section.
|
||||
* Remainders of CNAME chains are cut off and resolved by iterator. */
|
||||
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
|
||||
if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) != 0) {
|
||||
if(has_additional(rrset->type)) del_addi = 1;
|
||||
remove_rrset("sanitize: removing extraneous answer "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
|
||||
/* At this point, we brutally remove ALL rrsets that aren't
|
||||
* children of the originating zone. The idea here is that,
|
||||
* as far as we know, the server that we contacted is ONLY
|
||||
* authoritative for the originating zone. It, of course, MAY
|
||||
* be authoriative for any other zones, and of course, MAY
|
||||
* NOT be authoritative for some subdomains of the originating
|
||||
* zone. */
|
||||
prev = NULL;
|
||||
rrset = msg->rrset_first;
|
||||
while(rrset) {
|
||||
|
||||
/* remove private addresses */
|
||||
if( (rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA) &&
|
||||
priv_rrset_bad(ie->priv, pkt, rrset)) {
|
||||
|
||||
/* do not set servfail since this leads to too
|
||||
* many drops of other people using rfc1918 space */
|
||||
remove_rrset("sanitize: removing public name with "
|
||||
"private address", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip DNAME records -- they will always be followed by a
|
||||
* synthesized CNAME, which will be relevant.
|
||||
* FIXME: should this do something differently with DNAME
|
||||
* rrsets NOT in Section.ANSWER? */
|
||||
/* But since DNAME records are also subdomains of the zone,
|
||||
* same check can be used */
|
||||
|
||||
if(!pkt_sub(pkt, rrset->dname, zonename)) {
|
||||
if(msg->an_rrsets == 0 &&
|
||||
rrset->type == LDNS_RR_TYPE_NS &&
|
||||
rrset->section == LDNS_SECTION_AUTHORITY &&
|
||||
FLAGS_GET_RCODE(msg->flags) ==
|
||||
LDNS_RCODE_NOERROR && !soa_in_auth(msg) &&
|
||||
sub_of_pkt(pkt, zonename, rrset->dname)) {
|
||||
/* noerror, nodata and this NS rrset is above
|
||||
* the zone. This is LAME!
|
||||
* Leave in the NS for lame classification. */
|
||||
/* remove everything from the additional
|
||||
* (we dont want its glue that was approved
|
||||
* during the normalize action) */
|
||||
del_addi = 1;
|
||||
} else if(!env->cfg->harden_glue) {
|
||||
/* store in cache! Since it is relevant
|
||||
* (from normalize) it will be picked up
|
||||
* from the cache to be used later */
|
||||
store_rrset(pkt, msg, env, rrset);
|
||||
remove_rrset("sanitize: storing potential "
|
||||
"poison RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
} else {
|
||||
if(has_additional(rrset->type)) del_addi = 1;
|
||||
remove_rrset("sanitize: removing potential "
|
||||
"poison RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(del_addi && rrset->section == LDNS_SECTION_ADDITIONAL) {
|
||||
remove_rrset("sanitize: removing potential "
|
||||
"poison reference RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
/* check if right hand side of NSEC is within zone */
|
||||
if(rrset->type == LDNS_RR_TYPE_NSEC &&
|
||||
sanitize_nsec_is_overreach(rrset, zonename)) {
|
||||
remove_rrset("sanitize: removing overreaching NSEC "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
scrub_message(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct regional* region,
|
||||
struct module_env* env, struct iter_env* ie)
|
||||
{
|
||||
/* basic sanity checks */
|
||||
log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS,
|
||||
qinfo->qclass);
|
||||
if(msg->qdcount > 1)
|
||||
return 0;
|
||||
if( !(msg->flags&BIT_QR) )
|
||||
return 0;
|
||||
msg->flags &= ~(BIT_AD|BIT_Z); /* force off bit AD and Z */
|
||||
|
||||
/* make sure that a query is echoed back when NOERROR or NXDOMAIN */
|
||||
/* this is not required for basic operation but is a forgery
|
||||
* resistance (security) feature */
|
||||
if((FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR ||
|
||||
FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NXDOMAIN) &&
|
||||
msg->qdcount == 0)
|
||||
return 0;
|
||||
|
||||
/* if a query is echoed back, make sure it is correct. Otherwise,
|
||||
* this may be not a reply to our query. */
|
||||
if(msg->qdcount == 1) {
|
||||
if(dname_pkt_compare(pkt, msg->qname, qinfo->qname) != 0)
|
||||
return 0;
|
||||
if(msg->qtype != qinfo->qtype || msg->qclass != qinfo->qclass)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* normalize the response, this cleans up the additional. */
|
||||
if(!scrub_normalize(pkt, msg, qinfo, region))
|
||||
return 0;
|
||||
/* delete all out-of-zone information */
|
||||
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
69
contrib/unbound/iterator/iter_scrub.h
Normal file
69
contrib/unbound/iterator/iter_scrub.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* iterator/iter_scrub.h - scrubbing, normalization, sanitization of DNS msgs.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file has routine(s) for cleaning up incoming DNS messages from
|
||||
* possible useless or malicious junk in it.
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_ITER_SCRUB_H
|
||||
#define ITERATOR_ITER_SCRUB_H
|
||||
#include <ldns/buffer.h>
|
||||
struct msg_parse;
|
||||
struct query_info;
|
||||
struct regional;
|
||||
struct module_env;
|
||||
struct iter_env;
|
||||
|
||||
/**
|
||||
* Cleanup the passed dns message.
|
||||
* @param pkt: the packet itself, for resolving name compression pointers.
|
||||
* the packet buffer is unaltered.
|
||||
* @param msg: the parsed packet, this structure is cleaned up.
|
||||
* @param qinfo: the query info that was sent to the server. Checked.
|
||||
* @param zonename: the name of the last delegation point.
|
||||
* Used to determine out of bailiwick information.
|
||||
* @param regional: where to allocate (new) parts of the message.
|
||||
* @param env: module environment with config settings and cache.
|
||||
* @param ie: iterator module environment data.
|
||||
* @return: false if the message is total waste. true if scrubbed with success.
|
||||
*/
|
||||
int scrub_message(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct regional* regional,
|
||||
struct module_env* env, struct iter_env* ie);
|
||||
|
||||
#endif /* ITERATOR_ITER_SCRUB_H */
|
1034
contrib/unbound/iterator/iter_utils.c
Normal file
1034
contrib/unbound/iterator/iter_utils.c
Normal file
File diff suppressed because it is too large
Load Diff
334
contrib/unbound/iterator/iter_utils.h
Normal file
334
contrib/unbound/iterator/iter_utils.h
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* iterator/iter_utils.h - iterative resolver module utility functions.
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains functions to assist the iterator module.
|
||||
* Configuration options. Forward zones.
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_ITER_UTILS_H
|
||||
#define ITERATOR_ITER_UTILS_H
|
||||
#include "iterator/iter_resptype.h"
|
||||
#include <ldns/buffer.h>
|
||||
struct iter_env;
|
||||
struct iter_hints;
|
||||
struct iter_forwards;
|
||||
struct config_file;
|
||||
struct module_env;
|
||||
struct delegpt_addr;
|
||||
struct delegpt;
|
||||
struct regional;
|
||||
struct msg_parse;
|
||||
struct ub_randstate;
|
||||
struct query_info;
|
||||
struct reply_info;
|
||||
struct module_qstate;
|
||||
struct sock_list;
|
||||
struct ub_packed_rrset_key;
|
||||
|
||||
/**
|
||||
* Process config options and set iterator module state.
|
||||
* Sets default values if no config is found.
|
||||
* @param iter_env: iterator module state.
|
||||
* @param cfg: config options.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
int iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Select a valid, nice target to send query to.
|
||||
* Sorting and removing unsuitable targets is combined.
|
||||
*
|
||||
* @param iter_env: iterator module global state, with ip6 enabled and
|
||||
* do-not-query-addresses.
|
||||
* @param env: environment with infra cache (lameness, rtt info).
|
||||
* @param dp: delegation point with result list.
|
||||
* @param name: zone name (for lameness check).
|
||||
* @param namelen: length of name.
|
||||
* @param qtype: query type that we want to send.
|
||||
* @param dnssec_lame: set to 1, if a known dnssec-lame server is selected
|
||||
* these are not preferred, but are used as a last resort.
|
||||
* @param chase_to_rd: set to 1 if a known recursion lame server is selected
|
||||
* these are not preferred, but are used as a last resort.
|
||||
* @param open_target: number of currently outstanding target queries.
|
||||
* If we wait for these, perhaps more server addresses become available.
|
||||
* @param blacklist: the IP blacklist to use.
|
||||
* @return best target or NULL if no target.
|
||||
* if not null, that target is removed from the result list in the dp.
|
||||
*/
|
||||
struct delegpt_addr* iter_server_selection(struct iter_env* iter_env,
|
||||
struct module_env* env, struct delegpt* dp, uint8_t* name,
|
||||
size_t namelen, uint16_t qtype, int* dnssec_lame,
|
||||
int* chase_to_rd, int open_target, struct sock_list* blacklist);
|
||||
|
||||
/**
|
||||
* Allocate dns_msg from parsed msg, in regional.
|
||||
* @param pkt: packet.
|
||||
* @param msg: parsed message (cleaned and ready for regional allocation).
|
||||
* @param regional: regional to use for allocation.
|
||||
* @return newly allocated dns_msg, or NULL on memory error.
|
||||
*/
|
||||
struct dns_msg* dns_alloc_msg(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct regional* regional);
|
||||
|
||||
/**
|
||||
* Copy a dns_msg to this regional.
|
||||
* @param from: dns message, also in regional.
|
||||
* @param regional: regional to use for allocation.
|
||||
* @return newly allocated dns_msg, or NULL on memory error.
|
||||
*/
|
||||
struct dns_msg* dns_copy_msg(struct dns_msg* from, struct regional* regional);
|
||||
|
||||
/**
|
||||
* Allocate a dns_msg with malloc/alloc structure and store in dns cache.
|
||||
* @param env: environment, with alloc structure and dns cache.
|
||||
* @param qinf: query info, the query for which answer is stored.
|
||||
* @param rep: reply in dns_msg from dns_alloc_msg for example.
|
||||
* @param is_referral: If true, then the given message to be stored is a
|
||||
* referral. The cache implementation may use this as a hint.
|
||||
* @param leeway: prefetch TTL leeway to expire old rrsets quicker.
|
||||
* @param pside: true if dp is parentside, thus message is 'fresh' and NS
|
||||
* can be prefetch-updates.
|
||||
* @param region: to copy modified (cache is better) rrs back to.
|
||||
* @return 0 on alloc error (out of memory).
|
||||
*/
|
||||
int iter_dns_store(struct module_env* env, struct query_info* qinf,
|
||||
struct reply_info* rep, int is_referral, uint32_t leeway, int pside,
|
||||
struct regional* region);
|
||||
|
||||
/**
|
||||
* Select randomly with n/m probability.
|
||||
* For shuffle NS records for address fetching.
|
||||
* @param rnd: random table
|
||||
* @param n: probability.
|
||||
* @param m: divisor for probability.
|
||||
* @return true with n/m probability.
|
||||
*/
|
||||
int iter_ns_probability(struct ub_randstate* rnd, int n, int m);
|
||||
|
||||
/**
|
||||
* Mark targets that result in a dependency cycle as done, so they
|
||||
* will not get selected as targets.
|
||||
* @param qstate: query state.
|
||||
* @param dp: delegpt to mark ns in.
|
||||
*/
|
||||
void iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* Mark targets that result in a dependency cycle as done, so they
|
||||
* will not get selected as targets. For the parent-side lookups.
|
||||
* @param qstate: query state.
|
||||
* @param dp: delegpt to mark ns in.
|
||||
*/
|
||||
void iter_mark_pside_cycle_targets(struct module_qstate* qstate,
|
||||
struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* See if delegation is useful or offers immediately no targets for
|
||||
* further recursion.
|
||||
* @param qinfo: query name and type
|
||||
* @param qflags: query flags with RD flag
|
||||
* @param dp: delegpt to check.
|
||||
* @return true if dp is useless.
|
||||
*/
|
||||
int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
|
||||
struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* See if delegation is expected to have DNSSEC information (RRSIGs) in
|
||||
* its answers, or not. Inspects delegation point (name), trust anchors,
|
||||
* and delegation message (DS RRset) to determine this.
|
||||
* @param env: module env with trust anchors.
|
||||
* @param dp: delegation point.
|
||||
* @param msg: delegation message, with DS if a secure referral.
|
||||
* @param dclass: class of query.
|
||||
* @return 1 if dnssec is expected, 0 if not.
|
||||
*/
|
||||
int iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
|
||||
struct dns_msg* msg, uint16_t dclass);
|
||||
|
||||
/**
|
||||
* See if a message contains DNSSEC.
|
||||
* This is examined by looking for RRSIGs. With DNSSEC a valid answer,
|
||||
* nxdomain, nodata, referral or cname reply has RRSIGs in answer or auth
|
||||
* sections, sigs on answer data, SOA, DS, or NSEC/NSEC3 records.
|
||||
* @param msg: message to examine.
|
||||
* @return true if DNSSEC information was found.
|
||||
*/
|
||||
int iter_msg_has_dnssec(struct dns_msg* msg);
|
||||
|
||||
/**
|
||||
* See if a message is known to be from a certain zone.
|
||||
* This looks for SOA or NS rrsets, for answers.
|
||||
* For referrals, when one label is delegated, the zone is detected.
|
||||
* Does not look at signatures.
|
||||
* @param msg: the message to inspect.
|
||||
* @param dp: delegation point with zone name to look for.
|
||||
* @param type: type of message.
|
||||
* @param dclass: class of query.
|
||||
* @return true if message is certain to be from zone in dp->name.
|
||||
* false if not sure (empty msg), or not from the zone.
|
||||
*/
|
||||
int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
|
||||
enum response_type type, uint16_t dclass);
|
||||
|
||||
/**
|
||||
* Check if two replies are equal
|
||||
* For fallback procedures
|
||||
* @param p: reply one. The reply has rrset data pointers in region.
|
||||
* Does not check rrset-IDs
|
||||
* @param q: reply two
|
||||
* @param buf: scratch buffer.
|
||||
* @return if one and two are equal.
|
||||
*/
|
||||
int reply_equal(struct reply_info* p, struct reply_info* q, ldns_buffer* buf);
|
||||
|
||||
/**
|
||||
* Store parent-side rrset in seperate rrset cache entries for later
|
||||
* last-resort * lookups in case the child-side versions of this information
|
||||
* fails.
|
||||
* @param env: environment with cache, time, ...
|
||||
* @param rrset: the rrset to store (copied).
|
||||
* Failure to store is logged, but otherwise ignored.
|
||||
*/
|
||||
void iter_store_parentside_rrset(struct module_env* env,
|
||||
struct ub_packed_rrset_key* rrset);
|
||||
|
||||
/**
|
||||
* Store parent-side NS records from a referral message
|
||||
* @param env: environment with cache, time, ...
|
||||
* @param rep: response with NS rrset.
|
||||
* Failure to store is logged, but otherwise ignored.
|
||||
*/
|
||||
void iter_store_parentside_NS(struct module_env* env, struct reply_info* rep);
|
||||
|
||||
/**
|
||||
* Store parent-side negative element, the parentside rrset does not exist,
|
||||
* creates an rrset with empty rdata in the rrset cache with PARENTSIDE flag.
|
||||
* @param env: environment with cache, time, ...
|
||||
* @param qinfo: the identity of the rrset that is missing.
|
||||
* @param rep: delegation response or answer response, to glean TTL from.
|
||||
* (malloc) failure is logged but otherwise ignored.
|
||||
*/
|
||||
void iter_store_parentside_neg(struct module_env* env,
|
||||
struct query_info* qinfo, struct reply_info* rep);
|
||||
|
||||
/**
|
||||
* Add parent NS record if that exists in the cache. This is both new
|
||||
* information and acts like a timeout throttle on retries.
|
||||
* @param env: query env with rrset cache and time.
|
||||
* @param dp: delegation point to store result in. Also this dp is used to
|
||||
* see which NS name is needed.
|
||||
* @param region: region to alloc result in.
|
||||
* @param qinfo: pertinent information, the qclass.
|
||||
* @return false on malloc failure.
|
||||
* if true, the routine worked and if such cached information
|
||||
* existed dp->has_parent_side_NS is set true.
|
||||
*/
|
||||
int iter_lookup_parent_NS_from_cache(struct module_env* env,
|
||||
struct delegpt* dp, struct regional* region, struct query_info* qinfo);
|
||||
|
||||
/**
|
||||
* Add parent-side glue if that exists in the cache. This is both new
|
||||
* information and acts like a timeout throttle on retries to fetch them.
|
||||
* @param env: query env with rrset cache and time.
|
||||
* @param dp: delegation point to store result in. Also this dp is used to
|
||||
* see which NS name is needed.
|
||||
* @param region: region to alloc result in.
|
||||
* @param qinfo: pertinent information, the qclass.
|
||||
* @return: true, it worked, no malloc failures, and new addresses (lame)
|
||||
* have been added, giving extra options as query targets.
|
||||
*/
|
||||
int iter_lookup_parent_glue_from_cache(struct module_env* env,
|
||||
struct delegpt* dp, struct regional* region, struct query_info* qinfo);
|
||||
|
||||
/**
|
||||
* Lookup next root-hint or root-forward entry.
|
||||
* @param hints: the hints.
|
||||
* @param fwd: the forwards.
|
||||
* @param c: the class to start searching at. 0 means find first one.
|
||||
* @return false if no classes found, true if found and returned in c.
|
||||
*/
|
||||
int iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
|
||||
uint16_t* c);
|
||||
|
||||
/**
|
||||
* Remove DS records that are inappropriate before they are cached.
|
||||
* @param msg: the response to scrub.
|
||||
* @param ns: RRSET that is the NS record for the referral.
|
||||
* if NULL, then all DS records are removed from the authority section.
|
||||
* @param z: zone name that the response is from.
|
||||
*/
|
||||
void iter_scrub_ds(struct dns_msg* msg, struct ub_packed_rrset_key* ns,
|
||||
uint8_t* z);
|
||||
|
||||
/**
|
||||
* Remove query attempts from all available ips. For 0x20.
|
||||
* @param dp: delegpt.
|
||||
* @param d: decrease.
|
||||
*/
|
||||
void iter_dec_attempts(struct delegpt* dp, int d);
|
||||
|
||||
/**
|
||||
* Add retry counts from older delegpt to newer delegpt.
|
||||
* Does not waste time on timeout'd (or other failing) addresses.
|
||||
* @param dp: new delegationpoint.
|
||||
* @param old: old delegationpoint.
|
||||
*/
|
||||
void iter_merge_retry_counts(struct delegpt* dp, struct delegpt* old);
|
||||
|
||||
/**
|
||||
* See if a DS response (type ANSWER) is too low: a nodata answer with
|
||||
* a SOA record in the authority section at-or-below the qchase.qname.
|
||||
* Also returns true if we are not sure (i.e. empty message, CNAME nosig).
|
||||
* @param msg: the response.
|
||||
* @param dp: the dp name is used to check if the RRSIG gives a clue that
|
||||
* it was originated from the correct nameserver.
|
||||
* @return true if too low.
|
||||
*/
|
||||
int iter_ds_toolow(struct dns_msg* msg, struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* See if delegpt can go down a step to the qname or not
|
||||
* @param qinfo: the query name looked up.
|
||||
* @param dp: checked if the name can go lower to the qname
|
||||
* @return true if can go down, false if that would not be possible.
|
||||
* the current response seems to be the one and only, best possible, response.
|
||||
*/
|
||||
int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp);
|
||||
|
||||
#endif /* ITERATOR_ITER_UTILS_H */
|
2897
contrib/unbound/iterator/iterator.c
Normal file
2897
contrib/unbound/iterator/iterator.c
Normal file
File diff suppressed because it is too large
Load Diff
375
contrib/unbound/iterator/iterator.h
Normal file
375
contrib/unbound/iterator/iterator.h
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
* iterator/iterator.h - iterative resolver DNS query response module
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains a module that performs recusive iterative DNS query
|
||||
* processing.
|
||||
*/
|
||||
|
||||
#ifndef ITERATOR_ITERATOR_H
|
||||
#define ITERATOR_ITERATOR_H
|
||||
#include "services/outbound_list.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/module.h"
|
||||
struct delegpt;
|
||||
struct iter_hints;
|
||||
struct iter_forwards;
|
||||
struct iter_donotq;
|
||||
struct iter_prep_list;
|
||||
struct iter_priv;
|
||||
|
||||
/** max number of query restarts. Determines max number of CNAME chain. */
|
||||
#define MAX_RESTART_COUNT 8
|
||||
/** max number of referrals. Makes sure resolver does not run away */
|
||||
#define MAX_REFERRAL_COUNT 130
|
||||
/** max number of queries-sent-out. Make sure large NS set does not loop */
|
||||
#define MAX_SENT_COUNT 16
|
||||
/** at what query-sent-count to stop target fetch policy */
|
||||
#define TARGET_FETCH_STOP 3
|
||||
/** how nice is a server without further information, in msec
|
||||
* Equals rtt initial timeout value.
|
||||
*/
|
||||
#define UNKNOWN_SERVER_NICENESS 376
|
||||
/** maximum timeout before a host is deemed unsuitable, in msec.
|
||||
* After host_ttl this will be timed out and the host will be tried again.
|
||||
* Equals RTT_MAX_TIMEOUT
|
||||
*/
|
||||
#define USEFUL_SERVER_TOP_TIMEOUT 120000
|
||||
/** Number of lost messages in a row that get a host blacklisted.
|
||||
* With 16, a couple different queries have to time out and no working
|
||||
* queries are happening */
|
||||
#define USEFUL_SERVER_MAX_LOST 16
|
||||
/** number of retries on outgoing queries */
|
||||
#define OUTBOUND_MSG_RETRY 5
|
||||
/** RTT band, within this amount from the best, servers are chosen randomly.
|
||||
* Chosen so that the UNKNOWN_SERVER_NICENESS falls within the band of a
|
||||
* fast server, this causes server exploration as a side benefit. msec. */
|
||||
#define RTT_BAND 400
|
||||
/** Start value for blacklisting a host, 2*USEFUL_SERVER_TOP_TIMEOUT in sec */
|
||||
#define INFRA_BACKOFF_INITIAL 240
|
||||
|
||||
/**
|
||||
* Global state for the iterator.
|
||||
*/
|
||||
struct iter_env {
|
||||
/** A flag to indicate whether or not we have an IPv6 route */
|
||||
int supports_ipv6;
|
||||
|
||||
/** A flag to indicate whether or not we have an IPv4 route */
|
||||
int supports_ipv4;
|
||||
|
||||
/** A set of inetaddrs that should never be queried. */
|
||||
struct iter_donotq* donotq;
|
||||
|
||||
/** private address space and private domains */
|
||||
struct iter_priv* priv;
|
||||
|
||||
/** The maximum dependency depth that this resolver will pursue. */
|
||||
int max_dependency_depth;
|
||||
|
||||
/**
|
||||
* The target fetch policy for each dependency level. This is
|
||||
* described as a simple number (per dependency level):
|
||||
* negative numbers (usually just -1) mean fetch-all,
|
||||
* 0 means only fetch on demand, and
|
||||
* positive numbers mean to fetch at most that many targets.
|
||||
* array of max_dependency_depth+1 size.
|
||||
*/
|
||||
int* target_fetch_policy;
|
||||
};
|
||||
|
||||
/**
|
||||
* State of the iterator for a query.
|
||||
*/
|
||||
enum iter_state {
|
||||
/**
|
||||
* Externally generated queries start at this state. Query restarts are
|
||||
* reset to this state.
|
||||
*/
|
||||
INIT_REQUEST_STATE = 0,
|
||||
|
||||
/**
|
||||
* Root priming events reactivate here, most other events pass
|
||||
* through this naturally as the 2nd part of the INIT_REQUEST_STATE.
|
||||
*/
|
||||
INIT_REQUEST_2_STATE,
|
||||
|
||||
/**
|
||||
* Stub priming events reactivate here, most other events pass
|
||||
* through this naturally as the 3rd part of the INIT_REQUEST_STATE.
|
||||
*/
|
||||
INIT_REQUEST_3_STATE,
|
||||
|
||||
/**
|
||||
* Each time a delegation point changes for a given query or a
|
||||
* query times out and/or wakes up, this state is (re)visited.
|
||||
* This state is reponsible for iterating through a list of
|
||||
* nameserver targets.
|
||||
*/
|
||||
QUERYTARGETS_STATE,
|
||||
|
||||
/**
|
||||
* Responses to queries start at this state. This state handles
|
||||
* the decision tree associated with handling responses.
|
||||
*/
|
||||
QUERY_RESP_STATE,
|
||||
|
||||
/** Responses to priming queries finish at this state. */
|
||||
PRIME_RESP_STATE,
|
||||
|
||||
/** Collecting query class information, for qclass=ANY, when
|
||||
* it spawns off queries for every class, it returns here. */
|
||||
COLLECT_CLASS_STATE,
|
||||
|
||||
/** Find NS record to resolve DS record from, walking to the right
|
||||
* NS spot until we find it */
|
||||
DSNS_FIND_STATE,
|
||||
|
||||
/** Responses that are to be returned upstream end at this state.
|
||||
* As well as responses to target queries. */
|
||||
FINISHED_STATE
|
||||
};
|
||||
|
||||
/**
|
||||
* Per query state for the iterator module.
|
||||
*/
|
||||
struct iter_qstate {
|
||||
/**
|
||||
* State of the iterator module.
|
||||
* This is the state that event is in or should sent to -- all
|
||||
* requests should start with the INIT_REQUEST_STATE. All
|
||||
* responses should start with QUERY_RESP_STATE. Subsequent
|
||||
* processing of the event will change this state.
|
||||
*/
|
||||
enum iter_state state;
|
||||
|
||||
/**
|
||||
* Final state for the iterator module.
|
||||
* This is the state that responses should be routed to once the
|
||||
* response is final. For externally initiated queries, this
|
||||
* will be FINISHED_STATE, locally initiated queries will have
|
||||
* different final states.
|
||||
*/
|
||||
enum iter_state final_state;
|
||||
|
||||
/**
|
||||
* The depth of this query, this means the depth of recursion.
|
||||
* This address is needed for another query, which is an address
|
||||
* needed for another query, etc. Original client query has depth 0.
|
||||
*/
|
||||
int depth;
|
||||
|
||||
/**
|
||||
* The response
|
||||
*/
|
||||
struct dns_msg* response;
|
||||
|
||||
/**
|
||||
* This is a list of RRsets that must be prepended to the
|
||||
* ANSWER section of a response before being sent upstream.
|
||||
*/
|
||||
struct iter_prep_list* an_prepend_list;
|
||||
/** Last element of the prepend list */
|
||||
struct iter_prep_list* an_prepend_last;
|
||||
|
||||
/**
|
||||
* This is the list of RRsets that must be prepended to the
|
||||
* AUTHORITY section of the response before being sent upstream.
|
||||
*/
|
||||
struct iter_prep_list* ns_prepend_list;
|
||||
/** Last element of the authority prepend list */
|
||||
struct iter_prep_list* ns_prepend_last;
|
||||
|
||||
/** query name used for chasing the results. Initially the same as
|
||||
* the state qinfo, but after CNAMEs this will be different.
|
||||
* The query info used to elicit the results needed. */
|
||||
struct query_info qchase;
|
||||
/** query flags to use when chasing the answer (i.e. RD flag) */
|
||||
uint16_t chase_flags;
|
||||
/** true if we set RD bit because of last resort recursion lame query*/
|
||||
int chase_to_rd;
|
||||
|
||||
/**
|
||||
* This is the current delegation point for an in-progress query. This
|
||||
* object retains state as to which delegation targets need to be
|
||||
* (sub)queried for vs which ones have already been visited.
|
||||
*/
|
||||
struct delegpt* dp;
|
||||
|
||||
/** state for 0x20 fallback when capsfail happens, 0 not a fallback */
|
||||
int caps_fallback;
|
||||
/** state for capsfail: current server number to try */
|
||||
size_t caps_server;
|
||||
/** state for capsfail: stored query for comparisons */
|
||||
struct reply_info* caps_reply;
|
||||
|
||||
/** Current delegation message - returned for non-RD queries */
|
||||
struct dns_msg* deleg_msg;
|
||||
|
||||
/** number of outstanding target sub queries */
|
||||
int num_target_queries;
|
||||
|
||||
/** outstanding direct queries */
|
||||
int num_current_queries;
|
||||
|
||||
/** the number of times this query has been restarted. */
|
||||
int query_restart_count;
|
||||
|
||||
/** the number of times this query as followed a referral. */
|
||||
int referral_count;
|
||||
|
||||
/** number of queries fired off */
|
||||
int sent_count;
|
||||
|
||||
/**
|
||||
* The query must store NS records from referrals as parentside RRs
|
||||
* Enabled once it hits resolution problems, to throttle retries.
|
||||
* If enabled it is the pointer to the old delegation point with
|
||||
* the old retry counts for bad-nameserver-addresses.
|
||||
*/
|
||||
struct delegpt* store_parent_NS;
|
||||
|
||||
/**
|
||||
* The query is for parent-side glue(A or AAAA) for a nameserver.
|
||||
* If the item is seen as glue in a referral, and pside_glue is NULL,
|
||||
* then it is stored in pside_glue for later.
|
||||
* If it was never seen, at the end, then a negative caching element
|
||||
* must be created.
|
||||
* The (data or negative) RR cache element then throttles retries.
|
||||
*/
|
||||
int query_for_pside_glue;
|
||||
/** the parent-side-glue element (NULL if none, its first match) */
|
||||
struct ub_packed_rrset_key* pside_glue;
|
||||
|
||||
/** If nonNULL we are walking upwards from DS query to find NS */
|
||||
uint8_t* dsns_point;
|
||||
/** length of the dname in dsns_point */
|
||||
size_t dsns_point_len;
|
||||
|
||||
/**
|
||||
* expected dnssec information for this iteration step.
|
||||
* If dnssec rrsigs are expected and not given, the server is marked
|
||||
* lame (dnssec-lame).
|
||||
*/
|
||||
int dnssec_expected;
|
||||
|
||||
/**
|
||||
* We are expecting dnssec information, but we also know the server
|
||||
* is DNSSEC lame. The response need not be marked dnssec-lame again.
|
||||
*/
|
||||
int dnssec_lame_query;
|
||||
|
||||
/**
|
||||
* This is flag that, if true, means that this event is
|
||||
* waiting for a stub priming query.
|
||||
*/
|
||||
int wait_priming_stub;
|
||||
|
||||
/**
|
||||
* This is a flag that, if true, means that this query is
|
||||
* for (re)fetching glue from a zone. Since the address should
|
||||
* have been glue, query again to the servers that should have
|
||||
* been returning it as glue.
|
||||
* The delegation point must be set to the one that should *not*
|
||||
* be used when creating the state. A higher one will be attempted.
|
||||
*/
|
||||
int refetch_glue;
|
||||
|
||||
/** list of pending queries to authoritative servers. */
|
||||
struct outbound_list outlist;
|
||||
};
|
||||
|
||||
/**
|
||||
* List of prepend items
|
||||
*/
|
||||
struct iter_prep_list {
|
||||
/** next in list */
|
||||
struct iter_prep_list* next;
|
||||
/** rrset */
|
||||
struct ub_packed_rrset_key* rrset;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the iterator function block.
|
||||
* @return: function block with function pointers to iterator methods.
|
||||
*/
|
||||
struct module_func_block* iter_get_funcblock(void);
|
||||
|
||||
/**
|
||||
* Get iterator state as a string
|
||||
* @param state: to convert
|
||||
* @return constant string that is printable.
|
||||
*/
|
||||
const char* iter_state_to_string(enum iter_state state);
|
||||
|
||||
/**
|
||||
* See if iterator state is a response state
|
||||
* @param s: to inspect
|
||||
* @return true if response state.
|
||||
*/
|
||||
int iter_state_is_responsestate(enum iter_state s);
|
||||
|
||||
/** iterator init */
|
||||
int iter_init(struct module_env* env, int id);
|
||||
|
||||
/** iterator deinit */
|
||||
void iter_deinit(struct module_env* env, int id);
|
||||
|
||||
/** iterator operate on a query */
|
||||
void iter_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
struct outbound_entry* outbound);
|
||||
|
||||
/**
|
||||
* Return priming query results to interestes super querystates.
|
||||
*
|
||||
* Sets the delegation point and delegation message (not nonRD queries).
|
||||
* This is a callback from walk_supers.
|
||||
*
|
||||
* @param qstate: query state that finished.
|
||||
* @param id: module id.
|
||||
* @param super: the qstate to inform.
|
||||
*/
|
||||
void iter_inform_super(struct module_qstate* qstate, int id,
|
||||
struct module_qstate* super);
|
||||
|
||||
/** iterator cleanup query state */
|
||||
void iter_clear(struct module_qstate* qstate, int id);
|
||||
|
||||
/** iterator alloc size routine */
|
||||
size_t iter_get_mem(struct module_env* env, int id);
|
||||
|
||||
#endif /* ITERATOR_ITERATOR_H */
|
400
contrib/unbound/libunbound/context.c
Normal file
400
contrib/unbound/libunbound/context.c
Normal file
@ -0,0 +1,400 @@
|
||||
/*
|
||||
* libunbound/context.c - validating context for unbound internal use
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains the validator context structure.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "libunbound/context.h"
|
||||
#include "util/module.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
#include "services/modstack.h"
|
||||
#include "services/localzone.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
|
||||
int
|
||||
context_finalize(struct ub_ctx* ctx)
|
||||
{
|
||||
struct config_file* cfg = ctx->env->cfg;
|
||||
verbosity = cfg->verbosity;
|
||||
if(ctx->logfile_override)
|
||||
log_file(ctx->log_out);
|
||||
else log_init(cfg->logfile, cfg->use_syslog, NULL);
|
||||
config_apply(cfg);
|
||||
if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env))
|
||||
return UB_INITFAIL;
|
||||
ctx->local_zones = local_zones_create();
|
||||
if(!ctx->local_zones)
|
||||
return UB_NOMEM;
|
||||
if(!local_zones_apply_cfg(ctx->local_zones, cfg))
|
||||
return UB_INITFAIL;
|
||||
if(!ctx->env->msg_cache ||
|
||||
cfg->msg_cache_size != slabhash_get_size(ctx->env->msg_cache) ||
|
||||
cfg->msg_cache_slabs != ctx->env->msg_cache->size) {
|
||||
slabhash_delete(ctx->env->msg_cache);
|
||||
ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs,
|
||||
HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
|
||||
msgreply_sizefunc, query_info_compare,
|
||||
query_entry_delete, reply_info_delete, NULL);
|
||||
if(!ctx->env->msg_cache)
|
||||
return UB_NOMEM;
|
||||
}
|
||||
ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache,
|
||||
ctx->env->cfg, ctx->env->alloc);
|
||||
if(!ctx->env->rrset_cache)
|
||||
return UB_NOMEM;
|
||||
ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg);
|
||||
if(!ctx->env->infra_cache)
|
||||
return UB_NOMEM;
|
||||
ctx->finalized = 1;
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* a, const void* b)
|
||||
{
|
||||
if( *(int*)a < *(int*)b )
|
||||
return -1;
|
||||
if( *(int*)a > *(int*)b )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
context_query_delete(struct ctx_query* q)
|
||||
{
|
||||
if(!q) return;
|
||||
ub_resolve_free(q->res);
|
||||
free(q->msg);
|
||||
free(q);
|
||||
}
|
||||
|
||||
/** How many times to try to find an unused query-id-number for async */
|
||||
#define NUM_ID_TRIES 100000
|
||||
/** find next useful id number of 0 on error */
|
||||
static int
|
||||
find_id(struct ub_ctx* ctx, int* id)
|
||||
{
|
||||
size_t tries = 0;
|
||||
ctx->next_querynum++;
|
||||
while(rbtree_search(&ctx->queries, &ctx->next_querynum)) {
|
||||
ctx->next_querynum++; /* numerical wraparound is fine */
|
||||
if(tries++ > NUM_ID_TRIES)
|
||||
return 0;
|
||||
}
|
||||
*id = ctx->next_querynum;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ctx_query*
|
||||
context_new(struct ub_ctx* ctx, char* name, int rrtype, int rrclass,
|
||||
ub_callback_t cb, void* cbarg)
|
||||
{
|
||||
struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
|
||||
if(!q) return NULL;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(!find_id(ctx, &q->querynum)) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
q->node.key = &q->querynum;
|
||||
q->async = (cb != NULL);
|
||||
q->cb = cb;
|
||||
q->cb_arg = cbarg;
|
||||
q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
|
||||
if(!q->res) {
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
q->res->qname = strdup(name);
|
||||
if(!q->res->qname) {
|
||||
free(q->res);
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
q->res->qtype = rrtype;
|
||||
q->res->qclass = rrclass;
|
||||
|
||||
/* add to query list */
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(q->async)
|
||||
ctx->num_async ++;
|
||||
(void)rbtree_insert(&ctx->queries, &q->node);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return q;
|
||||
}
|
||||
|
||||
struct alloc_cache*
|
||||
context_obtain_alloc(struct ub_ctx* ctx, int locking)
|
||||
{
|
||||
struct alloc_cache* a;
|
||||
int tnum = 0;
|
||||
if(locking) {
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
}
|
||||
a = ctx->alloc_list;
|
||||
if(a)
|
||||
ctx->alloc_list = a->super; /* snip off list */
|
||||
else tnum = ctx->thr_next_num++;
|
||||
if(locking) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
if(a) {
|
||||
a->super = &ctx->superalloc;
|
||||
return a;
|
||||
}
|
||||
a = (struct alloc_cache*)calloc(1, sizeof(*a));
|
||||
if(!a)
|
||||
return NULL;
|
||||
alloc_init(a, &ctx->superalloc, tnum);
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc,
|
||||
int locking)
|
||||
{
|
||||
if(!ctx || !alloc)
|
||||
return;
|
||||
if(locking) {
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
}
|
||||
alloc->super = ctx->alloc_list;
|
||||
ctx->alloc_list = alloc;
|
||||
if(locking) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
context_serialize_new_query(struct ctx_query* q, uint32_t* len)
|
||||
{
|
||||
/* format for new query is
|
||||
* o uint32 cmd
|
||||
* o uint32 id
|
||||
* o uint32 type
|
||||
* o uint32 class
|
||||
* o rest queryname (string)
|
||||
*/
|
||||
uint8_t* p;
|
||||
size_t slen = strlen(q->res->qname) + 1/*end of string*/;
|
||||
*len = sizeof(uint32_t)*4 + slen;
|
||||
p = (uint8_t*)malloc(*len);
|
||||
if(!p) return NULL;
|
||||
ldns_write_uint32(p, UB_LIBCMD_NEWQUERY);
|
||||
ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
|
||||
ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype);
|
||||
ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass);
|
||||
memmove(p+4*sizeof(uint32_t), q->res->qname, slen);
|
||||
return p;
|
||||
}
|
||||
|
||||
struct ctx_query*
|
||||
context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
|
||||
{
|
||||
struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
|
||||
if(!q) return NULL;
|
||||
if(len < 4*sizeof(uint32_t)+1) {
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
log_assert( ldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
|
||||
q->querynum = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||
q->node.key = &q->querynum;
|
||||
q->async = 1;
|
||||
q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
|
||||
if(!q->res) {
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
q->res->qtype = (int)ldns_read_uint32(p+2*sizeof(uint32_t));
|
||||
q->res->qclass = (int)ldns_read_uint32(p+3*sizeof(uint32_t));
|
||||
q->res->qname = strdup((char*)(p+4*sizeof(uint32_t)));
|
||||
if(!q->res->qname) {
|
||||
free(q->res);
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** add to query list */
|
||||
ctx->num_async++;
|
||||
(void)rbtree_insert(&ctx->queries, &q->node);
|
||||
return q;
|
||||
}
|
||||
|
||||
struct ctx_query*
|
||||
context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
int querynum;
|
||||
if(len < 4*sizeof(uint32_t)+1) {
|
||||
return NULL;
|
||||
}
|
||||
log_assert( ldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
|
||||
querynum = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||
q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum);
|
||||
if(!q) {
|
||||
return NULL;
|
||||
}
|
||||
log_assert(q->async);
|
||||
return q;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
context_serialize_answer(struct ctx_query* q, int err, ldns_buffer* pkt,
|
||||
uint32_t* len)
|
||||
{
|
||||
/* answer format
|
||||
* o uint32 cmd
|
||||
* o uint32 id
|
||||
* o uint32 error_code
|
||||
* o uint32 msg_security
|
||||
* o uint32 length of why_bogus string (+1 for eos); 0 absent.
|
||||
* o why_bogus_string
|
||||
* o the remainder is the answer msg from resolver lookup.
|
||||
* remainder can be length 0.
|
||||
*/
|
||||
size_t pkt_len = pkt?ldns_buffer_remaining(pkt):0;
|
||||
size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0;
|
||||
uint8_t* p;
|
||||
*len = sizeof(uint32_t)*5 + pkt_len + wlen;
|
||||
p = (uint8_t*)malloc(*len);
|
||||
if(!p) return NULL;
|
||||
ldns_write_uint32(p, UB_LIBCMD_ANSWER);
|
||||
ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
|
||||
ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err);
|
||||
ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security);
|
||||
ldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)wlen);
|
||||
if(wlen > 0)
|
||||
memmove(p+5*sizeof(uint32_t), q->res->why_bogus, wlen);
|
||||
if(pkt_len > 0)
|
||||
memmove(p+5*sizeof(uint32_t)+wlen,
|
||||
ldns_buffer_begin(pkt), pkt_len);
|
||||
return p;
|
||||
}
|
||||
|
||||
struct ctx_query*
|
||||
context_deserialize_answer(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len, int* err)
|
||||
{
|
||||
struct ctx_query* q = NULL ;
|
||||
int id;
|
||||
size_t wlen;
|
||||
if(len < 5*sizeof(uint32_t)) return NULL;
|
||||
log_assert( ldns_read_uint32(p) == UB_LIBCMD_ANSWER);
|
||||
id = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||
q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
|
||||
if(!q) return NULL;
|
||||
*err = (int)ldns_read_uint32(p+2*sizeof(uint32_t));
|
||||
q->msg_security = ldns_read_uint32(p+3*sizeof(uint32_t));
|
||||
wlen = (size_t)ldns_read_uint32(p+4*sizeof(uint32_t));
|
||||
if(len > 5*sizeof(uint32_t) && wlen > 0) {
|
||||
if(len >= 5*sizeof(uint32_t)+wlen)
|
||||
q->res->why_bogus = (char*)memdup(
|
||||
p+5*sizeof(uint32_t), wlen);
|
||||
if(!q->res->why_bogus) {
|
||||
/* pass malloc failure to the user callback */
|
||||
q->msg_len = 0;
|
||||
*err = UB_NOMEM;
|
||||
return q;
|
||||
}
|
||||
q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */
|
||||
}
|
||||
if(len > 5*sizeof(uint32_t)+wlen) {
|
||||
q->msg_len = len - 5*sizeof(uint32_t) - wlen;
|
||||
q->msg = (uint8_t*)memdup(p+5*sizeof(uint32_t)+wlen,
|
||||
q->msg_len);
|
||||
if(!q->msg) {
|
||||
/* pass malloc failure to the user callback */
|
||||
q->msg_len = 0;
|
||||
*err = UB_NOMEM;
|
||||
return q;
|
||||
}
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
context_serialize_cancel(struct ctx_query* q, uint32_t* len)
|
||||
{
|
||||
/* format of cancel:
|
||||
* o uint32 cmd
|
||||
* o uint32 async-id */
|
||||
uint8_t* p = (uint8_t*)malloc(2*sizeof(uint32_t));
|
||||
if(!p) return NULL;
|
||||
*len = 2*sizeof(uint32_t);
|
||||
ldns_write_uint32(p, UB_LIBCMD_CANCEL);
|
||||
ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
|
||||
return p;
|
||||
}
|
||||
|
||||
struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
int id;
|
||||
if(len != 2*sizeof(uint32_t)) return NULL;
|
||||
log_assert( ldns_read_uint32(p) == UB_LIBCMD_CANCEL);
|
||||
id = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||
q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
|
||||
return q;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
context_serialize_quit(uint32_t* len)
|
||||
{
|
||||
uint8_t* p = (uint8_t*)malloc(sizeof(uint32_t));
|
||||
if(!p)
|
||||
return NULL;
|
||||
*len = sizeof(uint32_t);
|
||||
ldns_write_uint32(p, UB_LIBCMD_QUIT);
|
||||
return p;
|
||||
}
|
||||
|
||||
enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len)
|
||||
{
|
||||
uint32_t v;
|
||||
if((size_t)len < sizeof(v))
|
||||
return UB_LIBCMD_QUIT;
|
||||
v = ldns_read_uint32(p);
|
||||
return v;
|
||||
}
|
345
contrib/unbound/libunbound/context.h
Normal file
345
contrib/unbound/libunbound/context.h
Normal file
@ -0,0 +1,345 @@
|
||||
/*
|
||||
* libunbound/context.h - validating context for unbound internal use
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains the validator context structure.
|
||||
*/
|
||||
#ifndef LIBUNBOUND_CONTEXT_H
|
||||
#define LIBUNBOUND_CONTEXT_H
|
||||
#include "util/locks.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/rbtree.h"
|
||||
#include "services/modstack.h"
|
||||
#include "libunbound/unbound.h"
|
||||
#include "util/data/packed_rrset.h"
|
||||
struct libworker;
|
||||
struct tube;
|
||||
|
||||
/**
|
||||
* The context structure
|
||||
*
|
||||
* Contains two pipes for async service
|
||||
* qq : write queries to the async service pid/tid.
|
||||
* rr : read results from the async service pid/tid.
|
||||
*/
|
||||
struct ub_ctx {
|
||||
/* --- pipes --- */
|
||||
/** mutex on query write pipe */
|
||||
lock_basic_t qqpipe_lock;
|
||||
/** the query write pipe */
|
||||
struct tube* qq_pipe;
|
||||
/** mutex on result read pipe */
|
||||
lock_basic_t rrpipe_lock;
|
||||
/** the result read pipe */
|
||||
struct tube* rr_pipe;
|
||||
|
||||
/* --- shared data --- */
|
||||
/** mutex for access to env.cfg, finalized and dothread */
|
||||
lock_basic_t cfglock;
|
||||
/**
|
||||
* The context has been finalized
|
||||
* This is after config when the first resolve is done.
|
||||
* The modules are inited (module-init()) and shared caches created.
|
||||
*/
|
||||
int finalized;
|
||||
|
||||
/** is bg worker created yet ? */
|
||||
int created_bg;
|
||||
/** pid of bg worker process */
|
||||
pid_t bg_pid;
|
||||
/** tid of bg worker thread */
|
||||
ub_thread_t bg_tid;
|
||||
|
||||
/** do threading (instead of forking) for async resolution */
|
||||
int dothread;
|
||||
/** next thread number for new threads */
|
||||
int thr_next_num;
|
||||
/** if logfile is overriden */
|
||||
int logfile_override;
|
||||
/** what logfile to use instead */
|
||||
FILE* log_out;
|
||||
/**
|
||||
* List of alloc-cache-id points per threadnum for notinuse threads.
|
||||
* Simply the entire struct alloc_cache with the 'super' member used
|
||||
* to link a simply linked list. Reset super member to the superalloc
|
||||
* before use.
|
||||
*/
|
||||
struct alloc_cache* alloc_list;
|
||||
|
||||
/** shared caches, and so on */
|
||||
struct alloc_cache superalloc;
|
||||
/** module env master value */
|
||||
struct module_env* env;
|
||||
/** module stack */
|
||||
struct module_stack mods;
|
||||
/** local authority zones */
|
||||
struct local_zones* local_zones;
|
||||
/** random state used to seed new random state structures */
|
||||
struct ub_randstate* seed_rnd;
|
||||
|
||||
/** next query number (to try) to use */
|
||||
int next_querynum;
|
||||
/** number of async queries outstanding */
|
||||
size_t num_async;
|
||||
/**
|
||||
* Tree of outstanding queries. Indexed by querynum
|
||||
* Used when results come in for async to lookup.
|
||||
* Used when cancel is done for lookup (and delete).
|
||||
* Used to see if querynum is free for use.
|
||||
* Content of type ctx_query.
|
||||
*/
|
||||
rbtree_t queries;
|
||||
};
|
||||
|
||||
/**
|
||||
* The queries outstanding for the libunbound resolver.
|
||||
* These are outstanding for async resolution.
|
||||
* But also, outstanding for sync resolution by one of the threads that
|
||||
* has joined the threadpool.
|
||||
*/
|
||||
struct ctx_query {
|
||||
/** node in rbtree, must be first entry, key is ptr to the querynum */
|
||||
struct rbnode_t node;
|
||||
/** query id number, key for node */
|
||||
int querynum;
|
||||
/** was this an async query? */
|
||||
int async;
|
||||
/** was this query cancelled (for bg worker) */
|
||||
int cancelled;
|
||||
|
||||
/** for async query, the callback function */
|
||||
ub_callback_t cb;
|
||||
/** for async query, the callback user arg */
|
||||
void* cb_arg;
|
||||
|
||||
/** answer message, result from resolver lookup. */
|
||||
uint8_t* msg;
|
||||
/** resulting message length. */
|
||||
size_t msg_len;
|
||||
/** validation status on security */
|
||||
enum sec_status msg_security;
|
||||
/** store libworker that is handling this query */
|
||||
struct libworker* w;
|
||||
|
||||
/** result structure, also contains original query, type, class.
|
||||
* malloced ptr ready to hand to the client. */
|
||||
struct ub_result* res;
|
||||
};
|
||||
|
||||
/**
|
||||
* The error constants
|
||||
*/
|
||||
enum ub_ctx_err {
|
||||
/** no error */
|
||||
UB_NOERROR = 0,
|
||||
/** socket operation. Set to -1, so that if an error from _fd() is
|
||||
* passed (-1) it gives a socket error. */
|
||||
UB_SOCKET = -1,
|
||||
/** alloc failure */
|
||||
UB_NOMEM = -2,
|
||||
/** syntax error */
|
||||
UB_SYNTAX = -3,
|
||||
/** DNS service failed */
|
||||
UB_SERVFAIL = -4,
|
||||
/** fork() failed */
|
||||
UB_FORKFAIL = -5,
|
||||
/** cfg change after finalize() */
|
||||
UB_AFTERFINAL = -6,
|
||||
/** initialization failed (bad settings) */
|
||||
UB_INITFAIL = -7,
|
||||
/** error in pipe communication with async bg worker */
|
||||
UB_PIPE = -8,
|
||||
/** error reading from file (resolv.conf) */
|
||||
UB_READFILE = -9,
|
||||
/** error async_id does not exist or result already been delivered */
|
||||
UB_NOID = -10
|
||||
};
|
||||
|
||||
/**
|
||||
* Command codes for libunbound pipe.
|
||||
*
|
||||
* Serialization looks like this:
|
||||
* o length (of remainder) uint32.
|
||||
* o uint32 command code.
|
||||
* o per command format.
|
||||
*/
|
||||
enum ub_ctx_cmd {
|
||||
/** QUIT */
|
||||
UB_LIBCMD_QUIT = 0,
|
||||
/** New query, sent to bg worker */
|
||||
UB_LIBCMD_NEWQUERY,
|
||||
/** Cancel query, sent to bg worker */
|
||||
UB_LIBCMD_CANCEL,
|
||||
/** Query result, originates from bg worker */
|
||||
UB_LIBCMD_ANSWER
|
||||
};
|
||||
|
||||
/**
|
||||
* finalize a context.
|
||||
* @param ctx: context to finalize. creates shared data.
|
||||
* @return 0 if OK, or errcode.
|
||||
*/
|
||||
int context_finalize(struct ub_ctx* ctx);
|
||||
|
||||
/** compare two ctx_query elements */
|
||||
int context_query_cmp(const void* a, const void* b);
|
||||
|
||||
/**
|
||||
* delete context query
|
||||
* @param q: query to delete, including message packet and prealloc result
|
||||
*/
|
||||
void context_query_delete(struct ctx_query* q);
|
||||
|
||||
/**
|
||||
* Create new query in context, add to querynum list.
|
||||
* @param ctx: context
|
||||
* @param name: query name
|
||||
* @param rrtype: type
|
||||
* @param rrclass: class
|
||||
* @param cb: callback for async, or NULL for sync.
|
||||
* @param cbarg: user arg for async queries.
|
||||
* @return new ctx_query or NULL for malloc failure.
|
||||
*/
|
||||
struct ctx_query* context_new(struct ub_ctx* ctx, char* name, int rrtype,
|
||||
int rrclass, ub_callback_t cb, void* cbarg);
|
||||
|
||||
/**
|
||||
* Get a new alloc. Creates a new one or uses a cached one.
|
||||
* @param ctx: context
|
||||
* @param locking: if true, cfglock is locked while getting alloc.
|
||||
* @return an alloc, or NULL on mem error.
|
||||
*/
|
||||
struct alloc_cache* context_obtain_alloc(struct ub_ctx* ctx, int locking);
|
||||
|
||||
/**
|
||||
* Release an alloc. Puts it into the cache.
|
||||
* @param ctx: context
|
||||
* @param locking: if true, cfglock is locked while releasing alloc.
|
||||
* @param alloc: alloc to relinquish.
|
||||
*/
|
||||
void context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc,
|
||||
int locking);
|
||||
|
||||
/**
|
||||
* Serialize a context query that questions data.
|
||||
* This serializes the query name, type, ...
|
||||
* As well as command code 'new_query'.
|
||||
* @param q: context query
|
||||
* @param len: the length of the allocation is returned.
|
||||
* @return: an alloc, or NULL on mem error.
|
||||
*/
|
||||
uint8_t* context_serialize_new_query(struct ctx_query* q, uint32_t* len);
|
||||
|
||||
/**
|
||||
* Serialize a context_query result to hand back to user.
|
||||
* This serializes the query name, type, ..., and result.
|
||||
* As well as command code 'answer'.
|
||||
* @param q: context query
|
||||
* @param err: error code to pass to client.
|
||||
* @param pkt: the packet to add, can be NULL.
|
||||
* @param len: the length of the allocation is returned.
|
||||
* @return: an alloc, or NULL on mem error.
|
||||
*/
|
||||
uint8_t* context_serialize_answer(struct ctx_query* q, int err,
|
||||
ldns_buffer* pkt, uint32_t* len);
|
||||
|
||||
/**
|
||||
* Serialize a query cancellation. Serializes query async id
|
||||
* as well as command code 'cancel'
|
||||
* @param q: context query
|
||||
* @param len: the length of the allocation is returned.
|
||||
* @return: an alloc, or NULL on mem error.
|
||||
*/
|
||||
uint8_t* context_serialize_cancel(struct ctx_query* q, uint32_t* len);
|
||||
|
||||
/**
|
||||
* Serialize a 'quit' command.
|
||||
* @param len: the length of the allocation is returned.
|
||||
* @return: an alloc, or NULL on mem error.
|
||||
*/
|
||||
uint8_t* context_serialize_quit(uint32_t* len);
|
||||
|
||||
/**
|
||||
* Obtain command code from serialized buffer
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @return command code or QUIT on error.
|
||||
*/
|
||||
enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len);
|
||||
|
||||
/**
|
||||
* Lookup query from new_query buffer.
|
||||
* @param ctx: context
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @return looked up ctx_query or NULL for malloc failure.
|
||||
*/
|
||||
struct ctx_query* context_lookup_new_query(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len);
|
||||
|
||||
/**
|
||||
* Deserialize a new_query buffer.
|
||||
* @param ctx: context
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @return new ctx_query or NULL for malloc failure.
|
||||
*/
|
||||
struct ctx_query* context_deserialize_new_query(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len);
|
||||
|
||||
/**
|
||||
* Deserialize an answer buffer.
|
||||
* @param ctx: context
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @param err: error code to be returned to client is passed.
|
||||
* @return ctx_query with answer added or NULL for malloc failure.
|
||||
*/
|
||||
struct ctx_query* context_deserialize_answer(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len, int* err);
|
||||
|
||||
/**
|
||||
* Deserialize a cancel buffer.
|
||||
* @param ctx: context
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @return ctx_query to cancel or NULL for failure.
|
||||
*/
|
||||
struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len);
|
||||
|
||||
#endif /* LIBUNBOUND_CONTEXT_H */
|
1124
contrib/unbound/libunbound/libunbound.c
Normal file
1124
contrib/unbound/libunbound/libunbound.c
Normal file
File diff suppressed because it is too large
Load Diff
920
contrib/unbound/libunbound/libworker.c
Normal file
920
contrib/unbound/libunbound/libworker.c
Normal file
@ -0,0 +1,920 @@
|
||||
/*
|
||||
* libunbound/worker.c - worker thread or process that resolves
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains the worker process or thread that performs
|
||||
* the DNS resolving and validation. The worker is called by a procedure
|
||||
* and if in the background continues until exit, if in the foreground
|
||||
* returns from the procedure when done.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <ldns/dname.h>
|
||||
#include <ldns/wire2host.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include "libunbound/libworker.h"
|
||||
#include "libunbound/context.h"
|
||||
#include "libunbound/unbound.h"
|
||||
#include "services/outside_network.h"
|
||||
#include "services/mesh.h"
|
||||
#include "services/localzone.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/outbound_list.h"
|
||||
#include "util/module.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/random.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/netevent.h"
|
||||
#include "util/storage/lookup3.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/tube.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
|
||||
/** handle new query command for bg worker */
|
||||
static void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
|
||||
|
||||
/** delete libworker struct */
|
||||
static void
|
||||
libworker_delete(struct libworker* w)
|
||||
{
|
||||
if(!w) return;
|
||||
if(w->env) {
|
||||
outside_network_quit_prepare(w->back);
|
||||
mesh_delete(w->env->mesh);
|
||||
context_release_alloc(w->ctx, w->env->alloc,
|
||||
!w->is_bg || w->is_bg_thread);
|
||||
ldns_buffer_free(w->env->scratch_buffer);
|
||||
regional_destroy(w->env->scratch);
|
||||
forwards_delete(w->env->fwds);
|
||||
hints_delete(w->env->hints);
|
||||
ub_randfree(w->env->rnd);
|
||||
free(w->env);
|
||||
}
|
||||
SSL_CTX_free(w->sslctx);
|
||||
outside_network_delete(w->back);
|
||||
comm_base_delete(w->base);
|
||||
free(w);
|
||||
}
|
||||
|
||||
/** setup fresh libworker struct */
|
||||
static struct libworker*
|
||||
libworker_setup(struct ub_ctx* ctx, int is_bg)
|
||||
{
|
||||
unsigned int seed;
|
||||
struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
|
||||
struct config_file* cfg = ctx->env->cfg;
|
||||
int* ports;
|
||||
int numports;
|
||||
if(!w) return NULL;
|
||||
w->is_bg = is_bg;
|
||||
w->ctx = ctx;
|
||||
w->env = (struct module_env*)malloc(sizeof(*w->env));
|
||||
if(!w->env) {
|
||||
free(w);
|
||||
return NULL;
|
||||
}
|
||||
*w->env = *ctx->env;
|
||||
w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread);
|
||||
if(!w->env->alloc) {
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
w->thread_num = w->env->alloc->thread_num;
|
||||
alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
}
|
||||
w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
|
||||
w->env->scratch_buffer = ldns_buffer_new(cfg->msg_buffer_size);
|
||||
w->env->fwds = forwards_create();
|
||||
if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) {
|
||||
forwards_delete(w->env->fwds);
|
||||
w->env->fwds = NULL;
|
||||
}
|
||||
w->env->hints = hints_create();
|
||||
if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) {
|
||||
hints_delete(w->env->hints);
|
||||
w->env->hints = NULL;
|
||||
}
|
||||
if(cfg->ssl_upstream) {
|
||||
w->sslctx = connect_sslctx_create(NULL, NULL, NULL);
|
||||
if(!w->sslctx) {
|
||||
/* to make the setup fail after unlock */
|
||||
hints_delete(w->env->hints);
|
||||
w->env->hints = NULL;
|
||||
}
|
||||
}
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds ||
|
||||
!w->env->hints) {
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
w->env->worker = (struct worker*)w;
|
||||
w->env->probe_timer = NULL;
|
||||
seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
|
||||
(((unsigned int)w->thread_num)<<17);
|
||||
seed ^= (unsigned int)w->env->alloc->next_id;
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
}
|
||||
if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) {
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
seed = 0;
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
if(1) {
|
||||
/* primitive lockout for threading: if it overwrites another
|
||||
* thread it is like wiping the cache (which is likely empty
|
||||
* at the start) */
|
||||
/* note we are holding the ctx lock in normal threaded
|
||||
* cases so that is solved properly, it is only for many ctx
|
||||
* in different threads that this may clash */
|
||||
static int done_raninit = 0;
|
||||
if(!done_raninit) {
|
||||
done_raninit = 1;
|
||||
hash_set_raninit((uint32_t)ub_random(w->env->rnd));
|
||||
}
|
||||
}
|
||||
seed = 0;
|
||||
|
||||
w->base = comm_base_create(0);
|
||||
if(!w->base) {
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
}
|
||||
numports = cfg_condense_ports(cfg, &ports);
|
||||
if(numports == 0) {
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
w->back = outside_network_create(w->base, cfg->msg_buffer_size,
|
||||
(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
|
||||
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
cfg->do_tcp?cfg->outgoing_num_tcp:0,
|
||||
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
|
||||
ports, numports, cfg->unwanted_threshold,
|
||||
&libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx);
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
free(ports);
|
||||
if(!w->back) {
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
w->env->mesh = mesh_create(&ctx->mods, w->env);
|
||||
if(!w->env->mesh) {
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
w->env->send_query = &libworker_send_query;
|
||||
w->env->detach_subs = &mesh_detach_subs;
|
||||
w->env->attach_sub = &mesh_attach_sub;
|
||||
w->env->kill_sub = &mesh_state_delete;
|
||||
w->env->detect_cycle = &mesh_detect_cycle;
|
||||
comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
|
||||
return w;
|
||||
}
|
||||
|
||||
/** handle cancel command for bg worker */
|
||||
static void
|
||||
handle_cancel(struct libworker* w, uint8_t* buf, uint32_t len)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
if(w->is_bg_thread) {
|
||||
lock_basic_lock(&w->ctx->cfglock);
|
||||
q = context_deserialize_cancel(w->ctx, buf, len);
|
||||
lock_basic_unlock(&w->ctx->cfglock);
|
||||
} else {
|
||||
q = context_deserialize_cancel(w->ctx, buf, len);
|
||||
}
|
||||
if(!q) {
|
||||
/* probably simply lookup failed, i.e. the message had been
|
||||
* processed and answered before the cancel arrived */
|
||||
return;
|
||||
}
|
||||
q->cancelled = 1;
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/** do control command coming into bg server */
|
||||
static void
|
||||
libworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len)
|
||||
{
|
||||
switch(context_serial_getcmd(msg, len)) {
|
||||
default:
|
||||
case UB_LIBCMD_ANSWER:
|
||||
log_err("unknown command for bg worker %d",
|
||||
(int)context_serial_getcmd(msg, len));
|
||||
/* and fall through to quit */
|
||||
case UB_LIBCMD_QUIT:
|
||||
free(msg);
|
||||
comm_base_exit(w->base);
|
||||
break;
|
||||
case UB_LIBCMD_NEWQUERY:
|
||||
handle_newq(w, msg, len);
|
||||
break;
|
||||
case UB_LIBCMD_CANCEL:
|
||||
handle_cancel(w, msg, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** handle control command coming into server */
|
||||
void
|
||||
libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
|
||||
uint8_t* msg, size_t len, int err, void* arg)
|
||||
{
|
||||
struct libworker* w = (struct libworker*)arg;
|
||||
|
||||
if(err != 0) {
|
||||
free(msg);
|
||||
/* it is of no use to go on, exit */
|
||||
comm_base_exit(w->base);
|
||||
return;
|
||||
}
|
||||
libworker_do_cmd(w, msg, len); /* also frees the buf */
|
||||
}
|
||||
|
||||
/** the background thread func */
|
||||
static void*
|
||||
libworker_dobg(void* arg)
|
||||
{
|
||||
/* setup */
|
||||
uint32_t m;
|
||||
struct libworker* w = (struct libworker*)arg;
|
||||
struct ub_ctx* ctx;
|
||||
if(!w) {
|
||||
log_err("libunbound bg worker init failed, nomem");
|
||||
return NULL;
|
||||
}
|
||||
ctx = w->ctx;
|
||||
log_thread_set(&w->thread_num);
|
||||
#ifdef THREADS_DISABLED
|
||||
/* we are forked */
|
||||
w->is_bg_thread = 0;
|
||||
/* close non-used parts of the pipes */
|
||||
tube_close_write(ctx->qq_pipe);
|
||||
tube_close_read(ctx->rr_pipe);
|
||||
#endif
|
||||
if(!tube_setup_bg_listen(ctx->qq_pipe, w->base,
|
||||
libworker_handle_control_cmd, w)) {
|
||||
log_err("libunbound bg worker init failed, no bglisten");
|
||||
return NULL;
|
||||
}
|
||||
if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) {
|
||||
log_err("libunbound bg worker init failed, no bgwrite");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* do the work */
|
||||
comm_base_dispatch(w->base);
|
||||
|
||||
/* cleanup */
|
||||
m = UB_LIBCMD_QUIT;
|
||||
tube_remove_bg_listen(w->ctx->qq_pipe);
|
||||
tube_remove_bg_write(w->ctx->rr_pipe);
|
||||
libworker_delete(w);
|
||||
(void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m,
|
||||
(uint32_t)sizeof(m), 0);
|
||||
#ifdef THREADS_DISABLED
|
||||
/* close pipes from forked process before exit */
|
||||
tube_close_read(ctx->qq_pipe);
|
||||
tube_close_write(ctx->rr_pipe);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int libworker_bg(struct ub_ctx* ctx)
|
||||
{
|
||||
struct libworker* w;
|
||||
/* fork or threadcreate */
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->dothread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
w = libworker_setup(ctx, 1);
|
||||
if(!w) return UB_NOMEM;
|
||||
w->is_bg_thread = 1;
|
||||
#ifdef ENABLE_LOCK_CHECKS
|
||||
w->thread_num = 1; /* for nicer DEBUG checklocks */
|
||||
#endif
|
||||
ub_thread_create(&ctx->bg_tid, libworker_dobg, w);
|
||||
} else {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
#ifndef HAVE_FORK
|
||||
/* no fork on windows */
|
||||
return UB_FORKFAIL;
|
||||
#else /* HAVE_FORK */
|
||||
switch((ctx->bg_pid=fork())) {
|
||||
case 0:
|
||||
w = libworker_setup(ctx, 1);
|
||||
if(!w) fatal_exit("out of memory");
|
||||
/* close non-used parts of the pipes */
|
||||
tube_close_write(ctx->qq_pipe);
|
||||
tube_close_read(ctx->rr_pipe);
|
||||
(void)libworker_dobg(w);
|
||||
exit(0);
|
||||
break;
|
||||
case -1:
|
||||
return UB_FORKFAIL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif /* HAVE_FORK */
|
||||
}
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
/** get msg reply struct (in temp region) */
|
||||
static struct reply_info*
|
||||
parse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi)
|
||||
{
|
||||
struct reply_info* rep;
|
||||
struct msg_parse* msg;
|
||||
if(!(msg = regional_alloc(region, sizeof(*msg)))) {
|
||||
return NULL;
|
||||
}
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
ldns_buffer_set_position(pkt, 0);
|
||||
if(parse_packet(pkt, msg, region) != 0)
|
||||
return 0;
|
||||
if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
|
||||
return 0;
|
||||
}
|
||||
return rep;
|
||||
}
|
||||
|
||||
/** insert canonname */
|
||||
static int
|
||||
fill_canon(struct ub_result* res, uint8_t* s)
|
||||
{
|
||||
char buf[255+2];
|
||||
dname_str(s, buf);
|
||||
res->canonname = strdup(buf);
|
||||
return res->canonname != 0;
|
||||
}
|
||||
|
||||
/** fill data into result */
|
||||
static int
|
||||
fill_res(struct ub_result* res, struct ub_packed_rrset_key* answer,
|
||||
uint8_t* finalcname, struct query_info* rq)
|
||||
{
|
||||
size_t i;
|
||||
struct packed_rrset_data* data;
|
||||
if(!answer) {
|
||||
if(finalcname) {
|
||||
if(!fill_canon(res, finalcname))
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
res->data = (char**)calloc(1, sizeof(char*));
|
||||
res->len = (int*)calloc(1, sizeof(int));
|
||||
return (res->data && res->len);
|
||||
}
|
||||
data = (struct packed_rrset_data*)answer->entry.data;
|
||||
if(query_dname_compare(rq->qname, answer->rk.dname) != 0) {
|
||||
if(!fill_canon(res, answer->rk.dname))
|
||||
return 0; /* out of memory */
|
||||
} else res->canonname = NULL;
|
||||
res->data = (char**)calloc(data->count+1, sizeof(char*));
|
||||
res->len = (int*)calloc(data->count+1, sizeof(int));
|
||||
if(!res->data || !res->len)
|
||||
return 0; /* out of memory */
|
||||
for(i=0; i<data->count; i++) {
|
||||
/* remove rdlength from rdata */
|
||||
res->len[i] = (int)(data->rr_len[i] - 2);
|
||||
res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]);
|
||||
if(!res->data[i])
|
||||
return 0; /* out of memory */
|
||||
}
|
||||
res->data[data->count] = NULL;
|
||||
res->len[data->count] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** fill result from parsed message, on error fills servfail */
|
||||
void
|
||||
libworker_enter_result(struct ub_result* res, ldns_buffer* buf,
|
||||
struct regional* temp, enum sec_status msg_security)
|
||||
{
|
||||
struct query_info rq;
|
||||
struct reply_info* rep;
|
||||
res->rcode = LDNS_RCODE_SERVFAIL;
|
||||
rep = parse_reply(buf, temp, &rq);
|
||||
if(!rep) {
|
||||
log_err("cannot parse buf");
|
||||
return; /* error parsing buf, or out of memory */
|
||||
}
|
||||
if(!fill_res(res, reply_find_answer_rrset(&rq, rep),
|
||||
reply_find_final_cname_target(&rq, rep), &rq))
|
||||
return; /* out of memory */
|
||||
/* rcode, havedata, nxdomain, secure, bogus */
|
||||
res->rcode = (int)FLAGS_GET_RCODE(rep->flags);
|
||||
if(res->data && res->data[0])
|
||||
res->havedata = 1;
|
||||
if(res->rcode == LDNS_RCODE_NXDOMAIN)
|
||||
res->nxdomain = 1;
|
||||
if(msg_security == sec_status_secure)
|
||||
res->secure = 1;
|
||||
if(msg_security == sec_status_bogus)
|
||||
res->bogus = 1;
|
||||
}
|
||||
|
||||
/** fillup fg results */
|
||||
static void
|
||||
libworker_fillup_fg(struct ctx_query* q, int rcode, ldns_buffer* buf,
|
||||
enum sec_status s, char* why_bogus)
|
||||
{
|
||||
if(why_bogus)
|
||||
q->res->why_bogus = strdup(why_bogus);
|
||||
if(rcode != 0) {
|
||||
q->res->rcode = rcode;
|
||||
q->msg_security = s;
|
||||
return;
|
||||
}
|
||||
|
||||
q->res->rcode = LDNS_RCODE_SERVFAIL;
|
||||
q->msg_security = 0;
|
||||
q->msg = memdup(ldns_buffer_begin(buf), ldns_buffer_limit(buf));
|
||||
q->msg_len = ldns_buffer_limit(buf);
|
||||
if(!q->msg) {
|
||||
return; /* the error is in the rcode */
|
||||
}
|
||||
|
||||
/* canonname and results */
|
||||
q->msg_security = s;
|
||||
libworker_enter_result(q->res, buf, q->w->env->scratch, s);
|
||||
}
|
||||
|
||||
void
|
||||
libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s,
|
||||
char* why_bogus)
|
||||
{
|
||||
struct ctx_query* q = (struct ctx_query*)arg;
|
||||
/* fg query is done; exit comm base */
|
||||
comm_base_exit(q->w->base);
|
||||
|
||||
libworker_fillup_fg(q, rcode, buf, s, why_bogus);
|
||||
}
|
||||
|
||||
/** setup qinfo and edns */
|
||||
static int
|
||||
setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
|
||||
struct query_info* qinfo, struct edns_data* edns)
|
||||
{
|
||||
ldns_rdf* rdf;
|
||||
qinfo->qtype = (uint16_t)q->res->qtype;
|
||||
qinfo->qclass = (uint16_t)q->res->qclass;
|
||||
rdf = ldns_dname_new_frm_str(q->res->qname);
|
||||
if(!rdf) {
|
||||
return 0;
|
||||
}
|
||||
#ifdef UNBOUND_ALLOC_LITE
|
||||
qinfo->qname = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf));
|
||||
qinfo->qname_len = ldns_rdf_size(rdf);
|
||||
ldns_rdf_deep_free(rdf);
|
||||
rdf = 0;
|
||||
#else
|
||||
qinfo->qname = ldns_rdf_data(rdf);
|
||||
qinfo->qname_len = ldns_rdf_size(rdf);
|
||||
#endif
|
||||
edns->edns_present = 1;
|
||||
edns->ext_rcode = 0;
|
||||
edns->edns_version = 0;
|
||||
edns->bits = EDNS_DO;
|
||||
if(ldns_buffer_capacity(w->back->udp_buff) < 65535)
|
||||
edns->udp_size = (uint16_t)ldns_buffer_capacity(
|
||||
w->back->udp_buff);
|
||||
else edns->udp_size = 65535;
|
||||
ldns_rdf_free(rdf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
|
||||
{
|
||||
struct libworker* w = libworker_setup(ctx, 0);
|
||||
uint16_t qflags, qid;
|
||||
struct query_info qinfo;
|
||||
struct edns_data edns;
|
||||
if(!w)
|
||||
return UB_INITFAIL;
|
||||
if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
|
||||
libworker_delete(w);
|
||||
return UB_SYNTAX;
|
||||
}
|
||||
qid = 0;
|
||||
qflags = BIT_RD;
|
||||
q->w = w;
|
||||
/* see if there is a fixed answer */
|
||||
ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
|
||||
ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
|
||||
if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
|
||||
w->back->udp_buff, w->env->scratch)) {
|
||||
regional_free_all(w->env->scratch);
|
||||
libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
|
||||
w->back->udp_buff, sec_status_insecure, NULL);
|
||||
libworker_delete(w);
|
||||
free(qinfo.qname);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
/* process new query */
|
||||
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
|
||||
w->back->udp_buff, qid, libworker_fg_done_cb, q)) {
|
||||
free(qinfo.qname);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
free(qinfo.qname);
|
||||
|
||||
/* wait for reply */
|
||||
comm_base_dispatch(w->base);
|
||||
|
||||
libworker_delete(w);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
/** add result to the bg worker result queue */
|
||||
static void
|
||||
add_bg_result(struct libworker* w, struct ctx_query* q, ldns_buffer* pkt,
|
||||
int err, char* reason)
|
||||
{
|
||||
uint8_t* msg = NULL;
|
||||
uint32_t len = 0;
|
||||
|
||||
/* serialize and delete unneeded q */
|
||||
if(w->is_bg_thread) {
|
||||
lock_basic_lock(&w->ctx->cfglock);
|
||||
if(reason)
|
||||
q->res->why_bogus = strdup(reason);
|
||||
if(pkt) {
|
||||
q->msg_len = ldns_buffer_remaining(pkt);
|
||||
q->msg = memdup(ldns_buffer_begin(pkt), q->msg_len);
|
||||
if(!q->msg)
|
||||
msg = context_serialize_answer(q, UB_NOMEM,
|
||||
NULL, &len);
|
||||
else msg = context_serialize_answer(q, err,
|
||||
NULL, &len);
|
||||
} else msg = context_serialize_answer(q, err, NULL, &len);
|
||||
lock_basic_unlock(&w->ctx->cfglock);
|
||||
} else {
|
||||
if(reason)
|
||||
q->res->why_bogus = strdup(reason);
|
||||
msg = context_serialize_answer(q, err, pkt, &len);
|
||||
(void)rbtree_delete(&w->ctx->queries, q->node.key);
|
||||
w->ctx->num_async--;
|
||||
context_query_delete(q);
|
||||
}
|
||||
|
||||
if(!msg) {
|
||||
log_err("out of memory for async answer");
|
||||
return;
|
||||
}
|
||||
if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
|
||||
log_err("out of memory for async answer");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
libworker_bg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s,
|
||||
char* why_bogus)
|
||||
{
|
||||
struct ctx_query* q = (struct ctx_query*)arg;
|
||||
|
||||
if(q->cancelled) {
|
||||
if(q->w->is_bg_thread) {
|
||||
/* delete it now */
|
||||
struct ub_ctx* ctx = q->w->ctx;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
(void)rbtree_delete(&ctx->queries, q->node.key);
|
||||
ctx->num_async--;
|
||||
context_query_delete(q);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
/* cancelled, do not give answer */
|
||||
return;
|
||||
}
|
||||
q->msg_security = s;
|
||||
if(rcode != 0) {
|
||||
error_encode(buf, rcode, NULL, 0, BIT_RD, NULL);
|
||||
}
|
||||
add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus);
|
||||
}
|
||||
|
||||
|
||||
/** handle new query command for bg worker */
|
||||
static void
|
||||
handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
|
||||
{
|
||||
uint16_t qflags, qid;
|
||||
struct query_info qinfo;
|
||||
struct edns_data edns;
|
||||
struct ctx_query* q;
|
||||
if(w->is_bg_thread) {
|
||||
lock_basic_lock(&w->ctx->cfglock);
|
||||
q = context_lookup_new_query(w->ctx, buf, len);
|
||||
lock_basic_unlock(&w->ctx->cfglock);
|
||||
} else {
|
||||
q = context_deserialize_new_query(w->ctx, buf, len);
|
||||
}
|
||||
free(buf);
|
||||
if(!q) {
|
||||
log_err("failed to deserialize newq");
|
||||
return;
|
||||
}
|
||||
if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
|
||||
add_bg_result(w, q, NULL, UB_SYNTAX, NULL);
|
||||
return;
|
||||
}
|
||||
qid = 0;
|
||||
qflags = BIT_RD;
|
||||
/* see if there is a fixed answer */
|
||||
ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
|
||||
ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
|
||||
if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns,
|
||||
w->back->udp_buff, w->env->scratch)) {
|
||||
regional_free_all(w->env->scratch);
|
||||
q->msg_security = sec_status_insecure;
|
||||
add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL);
|
||||
free(qinfo.qname);
|
||||
return;
|
||||
}
|
||||
q->w = w;
|
||||
/* process new query */
|
||||
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
|
||||
w->back->udp_buff, qid, libworker_bg_done_cb, q)) {
|
||||
add_bg_result(w, q, NULL, UB_NOMEM, NULL);
|
||||
}
|
||||
free(qinfo.qname);
|
||||
}
|
||||
|
||||
void libworker_alloc_cleanup(void* arg)
|
||||
{
|
||||
struct libworker* w = (struct libworker*)arg;
|
||||
slabhash_clear(&w->env->rrset_cache->table);
|
||||
slabhash_clear(w->env->msg_cache);
|
||||
}
|
||||
|
||||
/** compare outbound entry qstates */
|
||||
static int
|
||||
outbound_entry_compare(void* a, void* b)
|
||||
{
|
||||
struct outbound_entry* e1 = (struct outbound_entry*)a;
|
||||
struct outbound_entry* e2 = (struct outbound_entry*)b;
|
||||
if(e1->qstate == e2->qstate)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
|
||||
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
|
||||
int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* zone, size_t zonelen, struct module_qstate* q)
|
||||
{
|
||||
struct libworker* w = (struct libworker*)q->env->worker;
|
||||
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
|
||||
q->region, sizeof(*e));
|
||||
if(!e)
|
||||
return NULL;
|
||||
e->qstate = q;
|
||||
e->qsent = outnet_serviced_query(w->back, qname,
|
||||
qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
|
||||
q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr,
|
||||
addrlen, zone, zonelen, libworker_handle_service_reply, e,
|
||||
w->back->udp_buff, &outbound_entry_compare);
|
||||
if(!e->qsent) {
|
||||
return NULL;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
int
|
||||
libworker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info)
|
||||
{
|
||||
struct module_qstate* q = (struct module_qstate*)arg;
|
||||
struct libworker* lw = (struct libworker*)q->env->worker;
|
||||
struct outbound_entry e;
|
||||
e.qstate = q;
|
||||
e.qsent = NULL;
|
||||
|
||||
if(error != 0) {
|
||||
mesh_report_reply(lw->env->mesh, &e, reply_info, error);
|
||||
return 0;
|
||||
}
|
||||
/* sanity check. */
|
||||
if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer))
|
||||
|| LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) !=
|
||||
LDNS_PACKET_QUERY
|
||||
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
|
||||
/* error becomes timeout for the module as if this reply
|
||||
* never arrived. */
|
||||
mesh_report_reply(lw->env->mesh, &e, reply_info,
|
||||
NETEVENT_TIMEOUT);
|
||||
return 0;
|
||||
}
|
||||
mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info)
|
||||
{
|
||||
struct outbound_entry* e = (struct outbound_entry*)arg;
|
||||
struct libworker* lw = (struct libworker*)e->qstate->env->worker;
|
||||
|
||||
if(error != 0) {
|
||||
mesh_report_reply(lw->env->mesh, e, reply_info, error);
|
||||
return 0;
|
||||
}
|
||||
/* sanity check. */
|
||||
if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer))
|
||||
|| LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) !=
|
||||
LDNS_PACKET_QUERY
|
||||
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
|
||||
/* error becomes timeout for the module as if this reply
|
||||
* never arrived. */
|
||||
mesh_report_reply(lw->env->mesh, e, reply_info,
|
||||
NETEVENT_TIMEOUT);
|
||||
return 0;
|
||||
}
|
||||
mesh_report_reply(lw->env->mesh, e, reply_info, NETEVENT_NOERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --- fake callbacks for fptr_wlist to work --- */
|
||||
void worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
|
||||
uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
|
||||
int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int worker_handle_request(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(repinfo))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int worker_handle_reply(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(repinfo))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remote_control_callback(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(repinfo))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname),
|
||||
size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
|
||||
uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
|
||||
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
|
||||
struct sockaddr_storage* ATTR_UNUSED(addr),
|
||||
socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
worker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void worker_stat_timer_cb(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void worker_probe_timer_cb(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void worker_start_accept(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void worker_stop_accept(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
#ifdef UB_ON_WINDOWS
|
||||
void
|
||||
worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
|
||||
ATTR_UNUSED(arg)) {
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void
|
||||
wsvc_cron_cb(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
#endif /* UB_ON_WINDOWS */
|
170
contrib/unbound/libunbound/libworker.h
Normal file
170
contrib/unbound/libunbound/libworker.h
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* libunbound/worker.h - worker thread or process that resolves
|
||||
*
|
||||
* Copyright (c) 2007, 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
|
||||
*
|
||||
* This file contains the worker process or thread that performs
|
||||
* the DNS resolving and validation. The worker is called by a procedure
|
||||
* and if in the background continues until exit, if in the foreground
|
||||
* returns from the procedure when done.
|
||||
*/
|
||||
#ifndef LIBUNBOUND_WORKER_H
|
||||
#define LIBUNBOUND_WORKER_H
|
||||
#include "util/data/packed_rrset.h"
|
||||
struct ub_ctx;
|
||||
struct ub_result;
|
||||
struct module_env;
|
||||
struct comm_base;
|
||||
struct outside_network;
|
||||
struct ub_randstate;
|
||||
struct ctx_query;
|
||||
struct outbound_entry;
|
||||
struct module_qstate;
|
||||
struct comm_point;
|
||||
struct comm_reply;
|
||||
struct regional;
|
||||
struct tube;
|
||||
|
||||
/**
|
||||
* The library-worker status structure
|
||||
* Internal to the worker.
|
||||
*/
|
||||
struct libworker {
|
||||
/** every worker has a unique thread_num. (first in struct) */
|
||||
int thread_num;
|
||||
/** context we are operating under */
|
||||
struct ub_ctx* ctx;
|
||||
|
||||
/** is this the bg worker? */
|
||||
int is_bg;
|
||||
/** is this a bg worker that is threaded (not forked)? */
|
||||
int is_bg_thread;
|
||||
|
||||
/** copy of the module environment with worker local entries. */
|
||||
struct module_env* env;
|
||||
/** the event base this worker works with */
|
||||
struct comm_base* base;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** random() table for this worker. */
|
||||
struct ub_randstate* rndstate;
|
||||
/** sslcontext for SSL wrapped DNS over TCP queries */
|
||||
void* sslctx;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a background worker
|
||||
* @param ctx: is updated with pid/tid of the background worker.
|
||||
* a new allocation cache is obtained from ctx. It contains the
|
||||
* threadnumber and unique id for further (shared) cache insertions.
|
||||
* @return 0 if OK, else error.
|
||||
* Further communication is done via the pipes in ctx.
|
||||
*/
|
||||
int libworker_bg(struct ub_ctx* ctx);
|
||||
|
||||
/**
|
||||
* Create a foreground worker.
|
||||
* This worker will join the threadpool of resolver threads.
|
||||
* It exits when the query answer has been obtained (or error).
|
||||
* This routine blocks until the worker is finished.
|
||||
* @param ctx: new allocation cache obtained and returned to it.
|
||||
* @param q: query (result is stored in here).
|
||||
* @return 0 if finished OK, else error.
|
||||
*/
|
||||
int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q);
|
||||
|
||||
/** cleanup the cache to remove all rrset IDs from it, arg is libworker */
|
||||
void libworker_alloc_cleanup(void* arg);
|
||||
|
||||
/**
|
||||
* Worker service routine to send serviced queries to authoritative servers.
|
||||
* @param qname: query name. (host order)
|
||||
* @param qnamelen: length in bytes of qname, including trailing 0.
|
||||
* @param qtype: query type. (host order)
|
||||
* @param qclass: query class. (host order)
|
||||
* @param flags: host order flags word, with opcode and CD bit.
|
||||
* @param dnssec: if set, EDNS record will have DO bit set.
|
||||
* @param want_dnssec: signatures needed.
|
||||
* @param addr: where to.
|
||||
* @param addrlen: length of addr.
|
||||
* @param zone: delegation point name.
|
||||
* @param zonelen: length of zone name wireformat dname.
|
||||
* @param q: wich query state to reactivate upon return.
|
||||
* @return: false on failure (memory or socket related). no query was
|
||||
* sent.
|
||||
*/
|
||||
struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
|
||||
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
|
||||
int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* zone, size_t zonelen, struct module_qstate* q);
|
||||
|
||||
/** process incoming replies from the network */
|
||||
int libworker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info);
|
||||
|
||||
/** process incoming serviced query replies from the network */
|
||||
int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info);
|
||||
|
||||
/** handle control command coming into server */
|
||||
void libworker_handle_control_cmd(struct tube* tube, uint8_t* msg, size_t len,
|
||||
int err, void* arg);
|
||||
|
||||
/** handle opportunity to write result back */
|
||||
void libworker_handle_result_write(struct tube* tube, uint8_t* msg, size_t len,
|
||||
int err, void* arg);
|
||||
|
||||
/** mesh callback with fg results */
|
||||
void libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf,
|
||||
enum sec_status s, char* why_bogus);
|
||||
|
||||
/** mesh callback with bg results */
|
||||
void libworker_bg_done_cb(void* arg, int rcode, ldns_buffer* buf,
|
||||
enum sec_status s, char* why_bogus);
|
||||
|
||||
/**
|
||||
* fill result from parsed message, on error fills servfail
|
||||
* @param res: is clear at start, filled in at end.
|
||||
* @param buf: contains DNS message.
|
||||
* @param temp: temporary buffer for parse.
|
||||
* @param msg_security: security status of the DNS message.
|
||||
* On error, the res may contain a different status
|
||||
* (out of memory is not secure, not bogus).
|
||||
*/
|
||||
void libworker_enter_result(struct ub_result* res, ldns_buffer* buf,
|
||||
struct regional* temp, enum sec_status msg_security);
|
||||
|
||||
#endif /* LIBUNBOUND_WORKER_H */
|
28
contrib/unbound/libunbound/python/LICENSE
Normal file
28
contrib/unbound/libunbound/python/LICENSE
Normal file
@ -0,0 +1,28 @@
|
||||
Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
|
||||
Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the organization 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 COPYRIGHT OWNER 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.
|
75
contrib/unbound/libunbound/python/Makefile
Normal file
75
contrib/unbound/libunbound/python/Makefile
Normal file
@ -0,0 +1,75 @@
|
||||
#
|
||||
# Makefile: compilation of pyUnbound and documentation, testing
|
||||
#
|
||||
# Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
|
||||
# Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
|
||||
#
|
||||
# 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 organization 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.
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " testenv to make test environment and run bash "
|
||||
@echo " usefull in case you don't want to install unbound but want to test examples"
|
||||
@echo " doc to make documentation"
|
||||
@echo " clean clean all"
|
||||
|
||||
.PHONY: testenv clean doc swig
|
||||
|
||||
#_unbound.so: ../../Makefile
|
||||
#$(MAKE) -C ../..
|
||||
|
||||
#../../.libs/libunbound.so.0: ../../Makefile
|
||||
#$(MAKE) -C ../..
|
||||
|
||||
#../../ldns-src/lib/libldns.so: ../../ldns-src/Makefile
|
||||
#$(MAKE) -C ../../ldns-src
|
||||
|
||||
clean:
|
||||
rm -rdf examples/unbound
|
||||
rm -f _unbound.so libunbound_wrap.o
|
||||
$(MAKE) -C ../.. clean
|
||||
|
||||
testenv: ../../.libs/libunbound.so.2 ../../ldns-src/lib/libldns.so ../../.libs/_unbound.so
|
||||
rm -rdf examples/unbound
|
||||
cd examples && mkdir unbound && ln -s ../../unbound.py unbound/__init__.py && ln -s ../../_unbound.so unbound/_unbound.so && ln -s ../../../../.libs/libunbound.so.2 unbound/libunbound.so.2 && ln -s ../../../../ldns-src/lib/libldns.so.1 unbound/libldns.so.1 && ls -la
|
||||
cd examples && if test -f ../../../.libs/_unbound.so; then cp ../../../.libs/_unbound.so . ; fi
|
||||
@echo "Run a script by typing ./script_name.py"
|
||||
cd examples && LD_LIBRARY_PATH=unbound bash
|
||||
rm -rdf examples/unbound examples/_unbound.so
|
||||
|
||||
doc: ../../.libs/libunbound.so.0 _unbound.so
|
||||
$(MAKE) -C docs html
|
||||
|
||||
#for development only
|
||||
swig: libunbound.i
|
||||
swig -python -o libunbound_wrap.c -I../.. libunbound.i
|
||||
gcc -c libunbound_wrap.c -O9 -fPIC -I../.. -I/usr/include/python2.5 -I. -o libunbound_wrap.o
|
||||
gcc -shared libunbound_wrap.o -L../../.libs -lunbound -o _unbound.so
|
||||
|
1
contrib/unbound/libunbound/python/doc/_static/readme
vendored
Normal file
1
contrib/unbound/libunbound/python/doc/_static/readme
vendored
Normal file
@ -0,0 +1 @@
|
||||
this directory exists to pacify sphinx-build.
|
181
contrib/unbound/libunbound/python/doc/conf.py
Normal file
181
contrib/unbound/libunbound/python/doc/conf.py
Normal file
@ -0,0 +1,181 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Unbound documentation build configuration file
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# The contents of this file are pickled, so don't put values in the namespace
|
||||
# that aren't pickleable (module imports are okay, they're removed automatically).
|
||||
#
|
||||
# All configuration values have a default value; values that are commented out
|
||||
# serve to show the default value.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If your extensions are in another directory, add it here. If the directory
|
||||
# is relative to the documentation root, use os.path.abspath to make it
|
||||
# absolute, like shown here.
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'../')))
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'../../../')))
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'../../../.libs/')))
|
||||
#print sys.path
|
||||
|
||||
# General configuration
|
||||
# ---------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General substitutions.
|
||||
project = 'pyUnbound'
|
||||
copyright = '2009, Zdenek Vasicek, Marek Vavrusa'
|
||||
|
||||
# The default replacements for |version| and |release|, also used in various
|
||||
# other places throughout the built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.0.0'
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of documents that shouldn't be included in the build.
|
||||
#unused_docs = []
|
||||
|
||||
# List of directories, relative to source directories, that shouldn't be searched
|
||||
# for source files.
|
||||
#exclude_dirs = []
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
|
||||
# Options for HTML output
|
||||
# -----------------------
|
||||
|
||||
# The style sheet to use for HTML and HTML Help pages. A file of that name
|
||||
# must exist either in Sphinx' static/ path, or in one of the custom paths
|
||||
# given in html_static_path.
|
||||
html_style = 'default.css'
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (within the static path) to place at the top of
|
||||
# the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
html_use_modindex = False
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, the reST sources are included in the HTML build as _sources/<name>.
|
||||
html_copy_source = False
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = ''
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'Unbounddoc'
|
||||
|
||||
|
||||
# Options for LaTeX output
|
||||
# ------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, document class [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'Unbound.tex', 'Unbound Documentation',
|
||||
'Zdenek Vasicek, Marek Vavrusa', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_use_modindex = True
|
26
contrib/unbound/libunbound/python/doc/examples/example1a.rst
Normal file
26
contrib/unbound/libunbound/python/doc/examples/example1a.rst
Normal file
@ -0,0 +1,26 @@
|
||||
.. _example_resolve_name:
|
||||
|
||||
==============================
|
||||
Resolve a name
|
||||
==============================
|
||||
|
||||
This basic example shows how to create a context and resolve a host address (DNS record of A type).
|
||||
|
||||
::
|
||||
|
||||
#!/usr/bin/python
|
||||
import unbound
|
||||
|
||||
ctx = unbound.ub_ctx()
|
||||
ctx.resolvconf("/etc/resolv.conf")
|
||||
|
||||
status, result = ctx.resolve("www.google.com")
|
||||
if status == 0 and result.havedata:
|
||||
print "Result.data:", result.data.address_list
|
||||
elif status != 0:
|
||||
print "Resolve error:", unbound.ub_strerror(status)
|
||||
|
||||
In contrast with C API, the source code is more compact while the performance of C implementation is preserved.
|
||||
The main advantage is that you need not take care about the deallocation and allocation of context and result structures; pyUnbound module do it automatically for you.
|
||||
|
||||
If only domain name is given, the :meth:`unbound.ub_ctx.resolve` looks for A records in IN class.
|
33
contrib/unbound/libunbound/python/doc/examples/example1b.rst
Normal file
33
contrib/unbound/libunbound/python/doc/examples/example1b.rst
Normal file
@ -0,0 +1,33 @@
|
||||
.. _example_reverse_lookup:
|
||||
|
||||
==============================
|
||||
Reverse DNS lookup
|
||||
==============================
|
||||
|
||||
Reverse DNS lookup involves determining the hostname associated with a given IP address.
|
||||
This example shows how reverse lookup can be done using unbound module.
|
||||
|
||||
For the reverse DNS records, the special domain in-addr.arpa is reserved.
|
||||
For example, a host name for the IP address 74.125.43.147 can be obtained by issuing a DNS query for the PTR record for address 147.43.125.74.in-addr.arpa.
|
||||
|
||||
::
|
||||
|
||||
#!/usr/bin/python
|
||||
import unbound
|
||||
|
||||
ctx = unbound.ub_ctx()
|
||||
ctx.resolvconf("/etc/resolv.conf")
|
||||
|
||||
status, result = ctx.resolve(unbound.reverse("74.125.43.147") + ".in-addr.arpa.", unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN)
|
||||
if status == 0 and result.havedata:
|
||||
print "Result.data:", result.data.domain_list
|
||||
elif status != 0:
|
||||
print "Resolve error:", unbound.ub_strerror(status)
|
||||
|
||||
In order to simplify the python code, unbound module contains function which reverses the hostname components.
|
||||
This function is defined as follows::
|
||||
|
||||
def reverse(domain):
|
||||
return '.'.join([a for a in domain.split(".")][::-1])
|
||||
|
||||
|
41
contrib/unbound/libunbound/python/doc/examples/example2.rst
Normal file
41
contrib/unbound/libunbound/python/doc/examples/example2.rst
Normal file
@ -0,0 +1,41 @@
|
||||
.. _example_setup_ctx:
|
||||
|
||||
==============================
|
||||
Lookup from threads
|
||||
==============================
|
||||
|
||||
This example shows how to use unbound module from a threaded program.
|
||||
In this example, three lookup threads are created which work in background.
|
||||
Each thread resolves different DNS record.
|
||||
|
||||
::
|
||||
|
||||
#!/usr/bin/python
|
||||
from unbound import ub_ctx, RR_TYPE_A, RR_CLASS_IN
|
||||
from threading import Thread
|
||||
|
||||
ctx = ub_ctx()
|
||||
ctx.resolvconf("/etc/resolv.conf")
|
||||
|
||||
class LookupThread(Thread):
|
||||
def __init__(self,ctx, name):
|
||||
Thread.__init__(self)
|
||||
self.ctx = ctx
|
||||
self.name = name
|
||||
|
||||
def run(self):
|
||||
print "Thread lookup started:",self.name
|
||||
status, result = self.ctx.resolve(self.name, RR_TYPE_A, RR_CLASS_IN)
|
||||
if status == 0 and result.havedata:
|
||||
print " Result:",self.name,":", result.data.address_list
|
||||
|
||||
threads = []
|
||||
for name in ["www.fit.vutbr.cz","www.vutbr.cz","www.google.com"]:
|
||||
thread = LookupThread(ctx, name)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
|
36
contrib/unbound/libunbound/python/doc/examples/example3.rst
Normal file
36
contrib/unbound/libunbound/python/doc/examples/example3.rst
Normal file
@ -0,0 +1,36 @@
|
||||
.. _example_asynch:
|
||||
|
||||
==============================
|
||||
Asynchronous lookup
|
||||
==============================
|
||||
|
||||
This example performs the name lookup in the background.
|
||||
The main program keeps running while the name is resolved.
|
||||
|
||||
::
|
||||
|
||||
#!/usr/bin/python
|
||||
import time
|
||||
import unbound
|
||||
|
||||
ctx = unbound.ub_ctx()
|
||||
ctx.resolvconf("/etc/resolv.conf")
|
||||
|
||||
def call_back(my_data,status,result):
|
||||
print "Call_back:", my_data
|
||||
if status == 0 and result.havedata:
|
||||
print "Result:", result.data.address_list
|
||||
my_data['done_flag'] = True
|
||||
|
||||
|
||||
my_data = {'done_flag':False,'arbitrary':"object"}
|
||||
status, async_id = ctx.resolve_async("www.seznam.cz", my_data, call_back, unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
|
||||
|
||||
while (status == 0) and (not my_data['done_flag']):
|
||||
status = ctx.process()
|
||||
time.sleep(0.1)
|
||||
|
||||
if (status != 0):
|
||||
print "Resolve error:", unbound.ub_strerror(status)
|
||||
|
||||
The :meth:`unbound.ub_ctx.resolve_async` method is able to pass on any Python object. In this example, we used a dictionary object `my_data`.
|
34
contrib/unbound/libunbound/python/doc/examples/example4.rst
Normal file
34
contrib/unbound/libunbound/python/doc/examples/example4.rst
Normal file
@ -0,0 +1,34 @@
|
||||
.. _example_examine:
|
||||
|
||||
==============================
|
||||
DNSSEC validator
|
||||
==============================
|
||||
|
||||
This example program performs DNSSEC validation of a DNS lookup.
|
||||
|
||||
::
|
||||
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
from unbound import ub_ctx,RR_TYPE_A,RR_CLASS_IN
|
||||
|
||||
ctx = ub_ctx()
|
||||
ctx.resolvconf("/etc/resolv.conf")
|
||||
if (os.path.isfile("keys")):
|
||||
ctx.add_ta_file("keys") #read public keys for DNSSEC verification
|
||||
|
||||
status, result = ctx.resolve("www.nic.cz", RR_TYPE_A, RR_CLASS_IN)
|
||||
if status == 0 and result.havedata:
|
||||
|
||||
print "Result:", result.data.address_list
|
||||
|
||||
if result.secure:
|
||||
print "Result is secure"
|
||||
elif result.bogus:
|
||||
print "Result is bogus"
|
||||
else:
|
||||
print "Result is insecure"
|
||||
|
||||
More detailed informations can be seen in libUnbound DNSSEC tutorial `here`_.
|
||||
|
||||
.. _here: http://www.unbound.net/documentation/libunbound-tutorial-6.html
|
29
contrib/unbound/libunbound/python/doc/examples/example5.rst
Normal file
29
contrib/unbound/libunbound/python/doc/examples/example5.rst
Normal file
@ -0,0 +1,29 @@
|
||||
.. _example_resolver_only:
|
||||
|
||||
==============================
|
||||
Resolver only
|
||||
==============================
|
||||
|
||||
This example program shows how to perform DNS resolution only.
|
||||
Unbound contains two basic modules: resolver and validator.
|
||||
In case, the validator is not necessary, the validator module can be turned off using "module-config" option.
|
||||
This option contains a list of module names separated by the space char. This list determined which modules should be employed and in what order.
|
||||
|
||||
::
|
||||
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
from unbound import ub_ctx,RR_TYPE_A,RR_CLASS_IN
|
||||
|
||||
ctx = ub_ctx()
|
||||
ctx.set_option("module-config:","iterator")
|
||||
ctx.resolvconf("/etc/resolv.conf")
|
||||
|
||||
status, result = ctx.resolve("www.google.com", RR_TYPE_A, RR_CLASS_IN)
|
||||
if status == 0 and result.havedata:
|
||||
|
||||
print "Result:", result.data.address_list
|
||||
|
||||
.. note::
|
||||
The :meth:`unbound.ub_ctx.set_option` method must be used before the first resolution (i.e. before :meth:`unbound.ub_ctx.resolve` or :meth:`unbound.ub_ctx.resolve_async` call).
|
||||
|
27
contrib/unbound/libunbound/python/doc/examples/example6-1.py
Normal file
27
contrib/unbound/libunbound/python/doc/examples/example6-1.py
Normal file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/python
|
||||
from unbound import ub_ctx,ub_strerror,RR_TYPE_A,RR_CLASS_IN
|
||||
|
||||
ctx = ub_ctx()
|
||||
ctx.resolvconf("/etc/resolv.conf")
|
||||
|
||||
status, result = ctx.resolve("test.record.xxx", RR_TYPE_A, RR_CLASS_IN)
|
||||
if status == 0 and result.havedata:
|
||||
print "Result:", result.data.address_list
|
||||
else:
|
||||
print "No record found"
|
||||
|
||||
#define new local zone
|
||||
status = ctx.zone_add("xxx.","static")
|
||||
if (status != 0): print "Error zone_add:",status, ub_strerror(status)
|
||||
|
||||
#add RR to the zone
|
||||
status = ctx.data_add("test.record.xxx. IN A 1.2.3.4")
|
||||
if (status != 0): print "Error data_add:",status, ub_strerror(status)
|
||||
|
||||
#lookup for an A record
|
||||
status, result = ctx.resolve("test.record.xxx", RR_TYPE_A, RR_CLASS_IN)
|
||||
if status == 0 and result.havedata:
|
||||
print "Result:", result.data.as_address_list()
|
||||
else:
|
||||
print "No record found"
|
||||
|
11
contrib/unbound/libunbound/python/doc/examples/example6.rst
Normal file
11
contrib/unbound/libunbound/python/doc/examples/example6.rst
Normal file
@ -0,0 +1,11 @@
|
||||
.. _example_localzone:
|
||||
|
||||
==============================
|
||||
Local zone manipulation
|
||||
==============================
|
||||
|
||||
This example program shows how to define local zone containing custom DNS records.
|
||||
|
||||
.. literalinclude:: example6-1.py
|
||||
:language: python
|
||||
|
17
contrib/unbound/libunbound/python/doc/examples/example7-1.py
Normal file
17
contrib/unbound/libunbound/python/doc/examples/example7-1.py
Normal file
@ -0,0 +1,17 @@
|
||||
#!/usr/bin/python
|
||||
# vim:fileencoding=utf-8
|
||||
#
|
||||
# IDN (Internationalized Domain Name) lookup support
|
||||
#
|
||||
import unbound
|
||||
|
||||
ctx = unbound.ub_ctx()
|
||||
ctx.resolvconf("/etc/resolv.conf")
|
||||
|
||||
status, result = ctx.resolve(u"www.háčkyčárky.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
|
||||
if status == 0 and result.havedata:
|
||||
print "Result:"
|
||||
print " raw data:", result.data
|
||||
for k in result.data.address_list:
|
||||
print " address:%s" % k
|
||||
|
16
contrib/unbound/libunbound/python/doc/examples/example7-2.py
Normal file
16
contrib/unbound/libunbound/python/doc/examples/example7-2.py
Normal file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/python
|
||||
# vim:fileencoding=utf-8
|
||||
#
|
||||
# IDN (Internationalized Domain Name) lookup support (lookup for MX)
|
||||
#
|
||||
import unbound
|
||||
|
||||
ctx = unbound.ub_ctx()
|
||||
ctx.resolvconf("/etc/resolv.conf")
|
||||
|
||||
status, result = ctx.resolve(u"háčkyčárky.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN)
|
||||
if status == 0 and result.havedata:
|
||||
print "Result:"
|
||||
print " raw data:", result.data
|
||||
for k in result.data.mx_list_idn:
|
||||
print " priority:%d address:%s" % k
|
18
contrib/unbound/libunbound/python/doc/examples/example7.rst
Normal file
18
contrib/unbound/libunbound/python/doc/examples/example7.rst
Normal file
@ -0,0 +1,18 @@
|
||||
.. _example_idna:
|
||||
|
||||
=================================================
|
||||
Internationalized domain name support
|
||||
=================================================
|
||||
|
||||
Unlike the libUnbound, pyUnbound is able to handle IDN queries.
|
||||
|
||||
.. literalinclude:: example7-1.py
|
||||
:language: python
|
||||
|
||||
If we use unicode string in :meth:`unbound.ub_ctx.resolve` method, the IDN DNAME conversion (if it is necessary) is performed on background.
|
||||
|
||||
.. literalinclude:: example7-2.py
|
||||
:language: python
|
||||
|
||||
The :class:`unbound.ub_data` class contains attributes suffix which converts the dname to UTF string. These attributes have the '_idn' suffix.
|
||||
Apart from this aproach, two conversion functions exist (:func:`unbound.idn2dname` and :func:`unbound.dname2idn`).
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user