Merge branch 'master' into dnsoverquic

This commit is contained in:
W.C.A. Wijngaards 2023-10-12 13:55:43 +02:00
commit 19868cc37f
60 changed files with 2181 additions and 680 deletions

View File

@ -747,7 +747,7 @@ msgencode.lo msgencode.o: $(srcdir)/util/data/msgencode.c config.h $(srcdir)/uti
msgparse.lo msgparse.o: $(srcdir)/util/data/msgparse.c config.h $(srcdir)/util/data/msgparse.h \
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/sldns/pkthdr.h \
$(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \
$(srcdir)/util/data/dname.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/regional.h $(srcdir)/sldns/sbuffer.h \
$(srcdir)/util/data/dname.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h $(srcdir)/sldns/sbuffer.h \
$(srcdir)/sldns/parseutil.h $(srcdir)/sldns/wire2str.h
msgreply.lo msgreply.o: $(srcdir)/util/data/msgreply.c config.h $(srcdir)/util/data/msgreply.h \
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/packed_rrset.h \
@ -802,7 +802,7 @@ iter_priv.lo iter_priv.o: $(srcdir)/iterator/iter_priv.c config.h $(srcdir)/iter
$(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/net_help.h \
$(srcdir)/util/storage/dnstree.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/sbuffer.h
iter_resptype.lo iter_resptype.o: $(srcdir)/iterator/iter_resptype.c config.h \
$(srcdir)/iterator/iter_resptype.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/util/log.h \
$(srcdir)/iterator/iter_resptype.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/iterator/iterator.h $(srcdir)/util/log.h \
$(srcdir)/services/cache/dns.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \
$(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/net_help.h \
$(srcdir)/util/data/dname.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/pkthdr.h

View File

@ -265,11 +265,11 @@ cachedb_init(struct module_env* env, int id)
return 0;
}
cachedb_env->enabled = 1;
if(env->cfg->serve_expired_reply_ttl)
if(env->cfg->serve_expired && env->cfg->serve_expired_reply_ttl)
log_warn(
"cachedb: serve-expired-reply-ttl is set but not working for data "
"originating from the external cache; 0 TLL is used for those.");
if(env->cfg->serve_expired_client_timeout)
"originating from the external cache; 0 TTL is used for those.");
if(env->cfg->serve_expired && env->cfg->serve_expired_client_timeout)
log_warn(
"cachedb: serve-expired-client-timeout is set but not working for "
"data originating from the external cache; expired data are used "

View File

@ -59,11 +59,28 @@ struct redis_moddata {
const char* server_path; /* server's unix path, or "", NULL if unused */
const char* server_password; /* server's AUTH password, or "", NULL if unused */
struct timeval timeout; /* timeout for connection setup and commands */
int logical_db; /* the redis logical database to use */
};
static redisReply* redis_command(struct module_env*, struct cachedb_env*,
const char*, const uint8_t*, size_t);
static void
moddata_clean(struct redis_moddata** moddata) {
if(!moddata || !*moddata)
return;
if((*moddata)->ctxs) {
int i;
for(i = 0; i < (*moddata)->numctxs; i++) {
if((*moddata)->ctxs[i])
redisFree((*moddata)->ctxs[i]);
}
free((*moddata)->ctxs);
}
free(*moddata);
*moddata = NULL;
}
static redisContext*
redis_connect(const struct redis_moddata* moddata)
{
@ -97,10 +114,21 @@ redis_connect(const struct redis_moddata* moddata)
}
freeReplyObject(rep);
}
if(moddata->logical_db > 0) {
redisReply* rep;
rep = redisCommand(ctx, "SELECT %d", moddata->logical_db);
if(!rep || rep->type == REDIS_REPLY_ERROR) {
log_err("failed to set logical database (%d)",
moddata->logical_db);
freeReplyObject(rep);
goto fail;
}
freeReplyObject(rep);
}
verbose(VERB_OPS, "Connection to Redis established");
return ctx;
fail:
fail:
if(ctx)
redisFree(ctx);
return NULL;
@ -117,14 +145,13 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
moddata = calloc(1, sizeof(struct redis_moddata));
if(!moddata) {
log_err("out of memory");
return 0;
goto fail;
}
moddata->numctxs = env->cfg->num_threads;
moddata->ctxs = calloc(env->cfg->num_threads, sizeof(redisContext*));
if(!moddata->ctxs) {
log_err("out of memory");
free(moddata);
return 0;
goto fail;
}
/* note: server_host is a shallow reference to configured string.
* we don't have to free it in this module. */
@ -134,8 +161,15 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
moddata->server_password = env->cfg->redis_server_password;
moddata->timeout.tv_sec = env->cfg->redis_timeout / 1000;
moddata->timeout.tv_usec = (env->cfg->redis_timeout % 1000) * 1000;
for(i = 0; i < moddata->numctxs; i++)
moddata->ctxs[i] = redis_connect(moddata);
moddata->logical_db = env->cfg->redis_logical_db;
for(i = 0; i < moddata->numctxs; i++) {
redisContext* ctx = redis_connect(moddata);
if(!ctx) {
log_err("redis_init: failed to init redis");
goto fail;
}
moddata->ctxs[i] = ctx;
}
cachedb_env->backend_data = moddata;
if(env->cfg->redis_expire_records) {
redisReply* rep = NULL;
@ -148,7 +182,7 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
log_err("redis_init: failed to init redis, the "
"redis-expire-records option requires the SETEX command "
"(redis >= 2.0.0)");
return 0;
goto fail;
}
redis_reply_type = rep->type;
freeReplyObject(rep);
@ -160,11 +194,14 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env)
log_err("redis_init: failed to init redis, the "
"redis-expire-records option requires the SETEX command "
"(redis >= 2.0.0)");
return 0;
goto fail;
}
}
return 1;
fail:
moddata_clean(&moddata);
return 0;
}
static void
@ -175,18 +212,7 @@ redis_deinit(struct module_env* env, struct cachedb_env* cachedb_env)
(void)env;
verbose(VERB_OPS, "Redis deinitialization");
if(!moddata)
return;
if(moddata->ctxs) {
int i;
for(i = 0; i < moddata->numctxs; i++) {
if(moddata->ctxs[i])
redisFree(moddata->ctxs[i]);
}
free(moddata->ctxs);
}
free(moddata);
moddata_clean(&moddata);
}
/*

607
configure vendored
View File

@ -4607,450 +4607,186 @@ fi
default_cflags=yes
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
set dummy ${ac_tool_prefix}gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
case $ac_cv_prog_cc_stdc in #(
no) :
ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #(
*) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
if ${ac_cv_prog_cc_c99+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
fi
if test -z "$ac_cv_prog_CC"; then
ac_ct_CC=$CC
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_ac_ct_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="gcc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
$as_echo "$ac_ct_CC" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
if test "x$ac_ct_CC" = x; then
CC=""
else
case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CC=$ac_ct_CC
fi
else
CC="$ac_cv_prog_CC"
fi
if test -z "$CC"; then
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}cc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
fi
fi
if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
ac_prog_rejected=no
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
ac_prog_rejected=yes
continue
fi
ac_cv_prog_CC="cc"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
if test $ac_prog_rejected = yes; then
# We found a bogon in the path, so make sure we never use it.
set dummy $ac_cv_prog_CC
shift
if test $# != 0; then
# We chose a different compiler from the bogus one.
# However, it has the same basename, so the bogon will be chosen
# first if we set CC to just the basename; use the full file name.
shift
ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
fi
fi
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
fi
if test -z "$CC"; then
if test -n "$ac_tool_prefix"; then
for ac_prog in cl.exe
do
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
$as_echo "$CC" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
test -n "$CC" && break
done
fi
if test -z "$CC"; then
ac_ct_CC=$CC
for ac_prog in cl.exe
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_prog_ac_ct_CC+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -n "$ac_ct_CC"; then
ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
$as_echo "$ac_ct_CC" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
test -n "$ac_ct_CC" && break
done
if test "x$ac_ct_CC" = x; then
CC=""
else
case $cross_compiling:$ac_tool_warned in
yes:)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CC=$ac_ct_CC
fi
fi
fi
test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "no acceptable C compiler found in \$PATH
See \`config.log' for more details" "$LINENO" 5; }
# Provide some information about the compiler.
$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
set X $ac_compile
ac_compiler=$2
for ac_option in --version -v -V -qversion; do
{ { ac_try="$ac_compiler $ac_option >&5"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
$as_echo "$ac_try_echo"; } >&5
(eval "$ac_compiler $ac_option >&5") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
sed '10a\
... rest of stderr output deleted ...
10q' conftest.err >conftest.er1
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
if ${ac_cv_c_compiler_gnu+:} false; then :
$as_echo_n "(cached) " >&6
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
ac_cv_prog_cc_c99=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <wchar.h>
#include <stdio.h>
int
main ()
// Check varargs macros. These examples are taken from C99 6.10.3.5.
#define debug(...) fprintf (stderr, __VA_ARGS__)
#define showlist(...) puts (#__VA_ARGS__)
#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
static void
test_varargs_macros (void)
{
#ifndef __GNUC__
choke me
int x = 1234;
int y = 5678;
debug ("Flag");
debug ("X = %d\n", x);
showlist (The first, second, and third items.);
report (x>y, "x is %d but y is %d", x, y);
}
// Check long long types.
#define BIG64 18446744073709551615ull
#define BIG32 4294967295ul
#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
#if !BIG_OK
your preprocessor is broken;
#endif
#if BIG_OK
#else
your preprocessor is broken;
#endif
static long long int bignum = -9223372036854775807LL;
static unsigned long long int ubignum = BIG64;
;
struct incomplete_array
{
int datasize;
double data[];
};
struct named_init {
int number;
const wchar_t *name;
double average;
};
typedef const char *ccp;
static inline int
test_restrict (ccp restrict text)
{
// See if C++-style comments work.
// Iterate through items via the restricted pointer.
// Also check for declarations in for loops.
for (unsigned int i = 0; *(text+i) != '\0'; ++i)
continue;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_compiler_gnu=yes
else
ac_compiler_gnu=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_cv_c_compiler_gnu=$ac_compiler_gnu
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
$as_echo "$ac_cv_c_compiler_gnu" >&6; }
if test $ac_compiler_gnu = yes; then
GCC=yes
else
GCC=
fi
ac_test_CFLAGS=${CFLAGS+set}
ac_save_CFLAGS=$CFLAGS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
$as_echo_n "checking whether $CC accepts -g... " >&6; }
if ${ac_cv_prog_cc_g+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_save_c_werror_flag=$ac_c_werror_flag
ac_c_werror_flag=yes
ac_cv_prog_cc_g=no
CFLAGS="-g"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
// Check varargs and va_copy.
static void
test_varargs (const char *format, ...)
{
va_list args;
va_start (args, format);
va_list args_copy;
va_copy (args_copy, args);
const char *str;
int number;
float fnumber;
while (*format)
{
switch (*format++)
{
case 's': // string
str = va_arg (args_copy, const char *);
break;
case 'd': // int
number = va_arg (args_copy, int);
break;
case 'f': // float
fnumber = va_arg (args_copy, double);
break;
default:
break;
}
}
va_end (args_copy);
va_end (args);
}
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_prog_cc_g=yes
else
CFLAGS=""
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
// Check bool.
_Bool success = false;
int
main ()
{
// Check restrict.
if (test_restrict ("String literal") == 0)
success = true;
char *restrict newvar = "Another string";
// Check varargs.
test_varargs ("s, d' f .", "string", 65, 34.234);
test_varargs_macros ();
// Check flexible array members.
struct incomplete_array *ia =
malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
ia->datasize = 10;
for (int i = 0; i < ia->datasize; ++i)
ia->data[i] = i * 1.234;
// Check named initializers.
struct named_init ni = {
.number = 34,
.name = L"Test wide string",
.average = 543.34343,
};
ni.number = 58;
int dynamic_array[ni.number];
dynamic_array[ni.number - 1] = 543;
// work around unused variable warnings
return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
|| dynamic_array[ni.number - 1] != 543);
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
do
CC="$ac_save_CC $ac_arg"
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_prog_cc_c99=$ac_arg
fi
rm -f core conftest.err conftest.$ac_objext
test "x$ac_cv_prog_cc_c99" != "xno" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
fi
# AC_CACHE_VAL
case "x$ac_cv_prog_cc_c99" in
x)
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
$as_echo "none needed" >&6; } ;;
xno)
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
$as_echo "unsupported" >&6; } ;;
*)
CC="$CC $ac_cv_prog_cc_c99"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
esac
if test "x$ac_cv_prog_cc_c99" != xno; then :
ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
else
ac_c_werror_flag=$ac_save_c_werror_flag
CFLAGS="-g"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
main ()
{
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_prog_cc_g=yes
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_c_werror_flag=$ac_save_c_werror_flag
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
$as_echo "$ac_cv_prog_cc_g" >&6; }
if test "$ac_test_CFLAGS" = set; then
CFLAGS=$ac_save_CFLAGS
elif test $ac_cv_prog_cc_g = yes; then
if test "$GCC" = yes; then
CFLAGS="-g -O2"
else
CFLAGS="-g"
fi
else
if test "$GCC" = yes; then
CFLAGS="-O2"
else
CFLAGS=
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
if ${ac_cv_prog_cc_c89+:} false; then :
$as_echo_n "(cached) " >&6
@ -5137,14 +4873,31 @@ $as_echo "unsupported" >&6; } ;;
$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
esac
if test "x$ac_cv_prog_cc_c89" != xno; then :
ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
else
ac_cv_prog_cc_stdc=no
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
fi
;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO Standard C" >&5
$as_echo_n "checking for $CC option to accept ISO Standard C... " >&6; }
if ${ac_cv_prog_cc_stdc+:} false; then :
$as_echo_n "(cached) " >&6
fi
case $ac_cv_prog_cc_stdc in #(
no) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
$as_echo "unsupported" >&6; } ;; #(
'') :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
$as_echo "none needed" >&6; } ;; #(
*) :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_stdc" >&5
$as_echo "$ac_cv_prog_cc_stdc" >&6; } ;;
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $CC dependency flag" >&5

View File

@ -280,7 +280,7 @@ ACX_CHECK_COMPILER_FLAG(g, [CFLAGS="$CFLAGS -g"])
ACX_CHECK_COMPILER_FLAG(O2, [CFLAGS="$CFLAGS -O2"])
default_cflags=yes
fi
AC_PROG_CC
m4_version_prereq([2.70], [AC_PROG_CC], [AC_PROG_CC_STDC])
ACX_DEPFLAG
ACX_DETERMINE_EXT_FLAGS_UNBOUND

View File

@ -590,7 +590,7 @@ ssl_read_line(RES* res, char* buf, size_t max)
while(1) {
ssize_t rr = recv(res->fd, buf+len, 1, 0);
if(rr <= 0) {
if(rr == 0) {
if(rr == 0 && len != 0) {
buf[len] = 0;
return 1;
}

View File

@ -66,6 +66,7 @@
#include "util/data/msgencode.h"
#include "util/data/dname.h"
#include "util/fptr_wlist.h"
#include "util/proxy_protocol.h"
#include "util/tube.h"
#include "util/edns.h"
#include "util/timeval_func.h"
@ -2319,6 +2320,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
worker->env.cfg->stat_interval);
worker_restart_timer(worker);
}
pp_init(&sldns_write_uint16, &sldns_write_uint32);
return 1;
}

View File

@ -1,3 +1,63 @@
11 October 2023: George
- Fix #850: [FR] Ability to use specific database in Redis, with new
redis-logical-db configuration option.
11 October 2023: Wouter
- Fix #949: "could not create control compt".
- Fix that cachedb does not warn when serve-expired is disabled about
use of serve-expired-reply-ttl and serve-expired-client-timeout.
- Fix for #949: Fix pythonmod/ubmodule-tst.py for Python 3.x.
10 October 2023: George
- Fix infinite loop when reading multiple lines of input on a broken
remote control socket. Addesses #947 and #948.
9 October 2023: Wouter
- Fix edns subnet so that queries with a source prefix of zero cause
the recursor send no edns subnet option to the upstream.
- Fix that printout of EDNS options shows the EDNS cookie option by
name.
4 October 2023: Wouter
- Fix #946: Forwarder returns servfail on upstream response noerror no
data.
3 October 2023: George
- Merge #881: Generalise the proxy protocol code.
2 October 2023: George
- Fix misplaced comment.
22 September 2023: Wouter
- Fix #942: 1.18.0 libunbound DNS regression when built without
OpenSSL.
18 September 2023: Wouter
- Fix rpz tcp-only action with rpz triggers nsdname and nsip.
15 September 2023: Wouter
- Merge #936: Check for c99 with autoconf versions prior to 2.70.
- Fix to remove two c99 notations.
14 September 2023: Wouter
- Fix authority zone answers for obscured DNAMEs and delegations.
8 September 2023: Wouter
- Fix send of udp retries when ENOBUFS is returned. It stops looping
and also waits for the condition to go away. Reported by Florian
Obser.
7 September 2023: Wouter
- Fix to scrub resource records of type A and AAAA that have an
inappropriate size. They are removed from responses.
- Fix to move msgparse_rrset_remove_rr code to util/msgparse.c.
- Fix to add EDE text when RRs have been removed due to length.
- Fix to set ede match in unit test for rr length removal.
- Fix to print EDE text in readable form in output logs.
6 September 2023: Wouter
- Merge #931: Prevent warnings from -Wmissing-prototypes.
31 August 2023: Wouter
- Fix autoconf 2.69 warnings in configure.
- Fix #927: unbound 1.18.0 make test error. Fix make test without SHA1.

View File

@ -1240,6 +1240,8 @@ remote-control:
# redis-timeout: 100
# # set timeout on redis records based on DNS response TTL
# redis-expire-records: no
# # redis logical database to use, 0 is the default database.
# redis-logical-db: 0
# IPSet
# Add specify domain into set via ipset.

View File

@ -2719,6 +2719,17 @@ Unbound is configured with \fBserve-expired\fR and \fBserve-expired-ttl\fR is 0,
this option is internally reverted to "no". Redis SETEX support is required
for this option (Redis >= 2.0.0).
This option defaults to no.
.TP
.B redis-logical-db: \fI<logical database index>
The logical database in Redis to use.
These are databases in the same Redis instance sharing the same configuration
and persisted in the same RDB/AOF file.
If unsure about using this option, Redis documentation
(https://redis.io/commands/select/) suggests not to use a single Redis instance
for multiple unrelated applications.
The default database in Redis is 0 while other logical databases need to be
explicitly SELECT'ed upon connecting.
This option defaults to 0.
.SS DNSTAP Logging Options
DNSTAP support, when compiled in by using \fB\-\-enable\-dnstap\fR, is enabled
in the \fBdnstap:\fR section.

View File

@ -75,6 +75,7 @@ int dynlibmod_init(struct module_env* env, int id) {
struct config_strlist* cfg_item = env->cfg->dynlib_file;
struct dynlibmod_env* de = (struct dynlibmod_env*)calloc(1, sizeof(struct dynlibmod_env));
__DYNMOD dynamic_library;
int i;
if (!de)
{
log_err("dynlibmod[%d]: malloc failure", dynlib_mod_idx);
@ -84,7 +85,7 @@ int dynlibmod_init(struct module_env* env, int id) {
env->modinfo[id] = (void*) de;
de->fname = NULL;
for(int i = dynlib_mod_idx;
for(i = dynlib_mod_idx;
i != 0 && cfg_item != NULL;
i--, cfg_item = cfg_item->next) {}

View File

@ -156,6 +156,7 @@ int ecs_whitelist_check(struct query_info* qinfo,
qstate->no_cache_store = 0;
}
sq->subnet_sent_no_subnet = 0;
if(sq->ecs_server_out.subnet_validdata && ((sq->subnet_downstream &&
qstate->env->cfg->client_subnet_always_forward) ||
ecs_is_whitelisted(sn_env->whitelist,
@ -166,6 +167,14 @@ int ecs_whitelist_check(struct query_info* qinfo,
* set. */
if(!edns_opt_list_find(qstate->edns_opts_back_out,
qstate->env->cfg->client_subnet_opcode)) {
/* if the client is not wanting an EDNS subnet option,
* omit it and store that we omitted it but actually
* are doing EDNS subnet to the server. */
if(sq->ecs_server_out.subnet_source_mask == 0) {
sq->subnet_sent_no_subnet = 1;
sq->subnet_sent = 0;
return 1;
}
subnet_ecs_opt_list_append(&sq->ecs_server_out,
&qstate->edns_opts_back_out, qstate, region);
}
@ -515,7 +524,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
}
/* We have not asked for subnet data */
if (!sq->subnet_sent) {
if (!sq->subnet_sent && !sq->subnet_sent_no_subnet) {
if (s_in->subnet_validdata)
verbose(VERB_QUERY, "subnetcache: received spurious data");
if (sq->subnet_downstream) /* Copy back to client */
@ -524,7 +533,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
}
/* subnet sent but nothing came back */
if (!s_in->subnet_validdata) {
if (!s_in->subnet_validdata && !sq->subnet_sent_no_subnet) {
/* The authority indicated no support for edns subnet. As a
* consequence the answer ended up in the regular cache. It
* is still useful to put it in the edns subnet cache for
@ -540,6 +549,18 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
return module_finished;
}
/* Purposefully there was no sent subnet, and there is consequently
* no subnet in the answer. If there was, use the subnet in the answer
* anyway. But if there is not, treat it as a prefix 0 answer. */
if(sq->subnet_sent_no_subnet && !s_in->subnet_validdata) {
/* Fill in 0.0.0.0/0 scope 0, or ::0/0 scope 0, for caching. */
s_in->subnet_addr_fam = s_out->subnet_addr_fam;
s_in->subnet_source_mask = 0;
s_in->subnet_scope_mask = 0;
memset(s_in->subnet_addr, 0, INET6_SIZE);
s_in->subnet_validdata = 1;
}
/* Being here means we have asked for and got a subnet specific
* answer. Also, the answer from the authority is not yet cached
* anywhere. */
@ -556,6 +577,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
(void)edns_opt_list_remove(&qstate->edns_opts_back_out,
qstate->env->cfg->client_subnet_opcode);
sq->subnet_sent = 0;
sq->subnet_sent_no_subnet = 0;
return module_restart_next;
}
@ -676,6 +698,7 @@ ecs_query_response(struct module_qstate* qstate, struct dns_msg* response,
edns_opt_list_remove(&qstate->edns_opts_back_out,
qstate->env->cfg->client_subnet_opcode);
sq->subnet_sent = 0;
sq->subnet_sent_no_subnet = 0;
memset(&sq->ecs_server_out, 0, sizeof(sq->ecs_server_out));
} else if (!sq->track_max_scope &&
FLAGS_GET_RCODE(response->rep->flags) == LDNS_RCODE_NOERROR &&
@ -737,6 +760,9 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
sq->ecs_server_in.subnet_scope_mask >
sq->max_scope))
sq->max_scope = sq->ecs_server_in.subnet_scope_mask;
} else if(sq->subnet_sent_no_subnet) {
/* The answer can be stored as scope 0, not in global cache. */
qstate->no_cache_store = 1;
}
return 1;

View File

@ -85,6 +85,13 @@ struct subnet_qstate {
struct ecs_data ecs_server_out;
int subnet_downstream;
int subnet_sent;
/**
* If there was no subnet sent because the client used source prefix
* length 0 for omitting the information. Then the answer is cached
* like subnet was a /0 scope. Like the subnet_sent flag, but when
* the EDNS subnet option is omitted because the client asked.
*/
int subnet_sent_no_subnet;
/** keep track of longest received scope, set after receiving CNAME for
* incoming QNAME. */
int track_max_scope;

View File

@ -207,28 +207,6 @@ size_t priv_get_mem(struct iter_priv* priv)
return sizeof(*priv) + regional_get_mem(priv->region);
}
/** remove RR from msgparse RRset, return true if rrset is entirely bad */
static int
remove_rr(const char* str, sldns_buffer* pkt, struct rrset_parse* rrset,
struct rr_parse* prev, struct rr_parse** rr, struct sockaddr_storage* addr, socklen_t addrlen)
{
if(verbosity >= VERB_QUERY && rrset->dname_len <= LDNS_MAX_DOMAINLEN && str) {
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
dname_pkt_copy(pkt, buf, rrset->dname);
log_name_addr(VERB_QUERY, str, buf, addr, addrlen);
}
if(prev)
prev->next = (*rr)->next;
else rrset->rr_first = (*rr)->next;
if(rrset->rr_last == *rr)
rrset->rr_last = prev;
rrset->rr_count --;
rrset->size -= (*rr)->size;
/* rr struct still exists, but is unlinked, so that in the for loop
* the rr->next works fine to continue. */
return rrset->rr_count == 0;
}
int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
struct rrset_parse* rrset)
{
@ -261,7 +239,7 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
INET_SIZE);
memmove(&addr, &sa, len);
if(priv_lookup_addr(priv, &addr, len)) {
if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len))
if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len))
return 1;
continue;
}
@ -284,7 +262,7 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
INET6_SIZE);
memmove(&addr, &sa, len);
if(priv_lookup_addr(priv, &addr, len)) {
if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len))
if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len))
return 1;
continue;
}

View File

@ -42,6 +42,7 @@
#include "config.h"
#include "iterator/iter_resptype.h"
#include "iterator/iter_delegpt.h"
#include "iterator/iterator.h"
#include "services/cache/dns.h"
#include "util/net_help.h"
#include "util/data/dname.h"
@ -105,7 +106,8 @@ response_type_from_cache(struct dns_msg* msg,
enum response_type
response_type_from_server(int rdset,
struct dns_msg* msg, struct query_info* request, struct delegpt* dp)
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
int* empty_nodata_found)
{
uint8_t* origzone = (uint8_t*)"\000"; /* the default */
struct ub_packed_rrset_key* s;
@ -284,13 +286,22 @@ response_type_from_server(int rdset,
/* If we've gotten this far, this is NOERROR/NODATA (which could
* be an entirely empty message) */
/* but ignore entirely empty messages, noerror/nodata has a soa
* negative ttl value in the authority section, this makes it try
* again at another authority. And turns it from a 5 second empty
* message into a 5 second servfail response. */
/* For entirely empty messages, try again, at first, then accept
* it it happens more. A regular noerror/nodata response has a soa
* negative ttl value in the authority section. This makes it try
* again at another authority. And decides between storing a 5 second
* empty message or a 5 second servfail response. */
if(msg->rep->an_numrrsets == 0 && msg->rep->ns_numrrsets == 0 &&
msg->rep->ar_numrrsets == 0)
return RESPONSE_TYPE_THROWAWAY;
msg->rep->ar_numrrsets == 0) {
if(empty_nodata_found) {
/* detect as throwaway at first, but accept later. */
(*empty_nodata_found)++;
if(*empty_nodata_found < EMPTY_NODATA_RETRY_COUNT)
return RESPONSE_TYPE_THROWAWAY;
return RESPONSE_TYPE_ANSWER;
}
return RESPONSE_TYPE_ANSWER;
}
/* 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;

View File

@ -119,9 +119,11 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
* @param request: the request that generated the response.
* @param dp: The delegation point that was being queried
* when the response was returned.
* @param empty_nodata_found: flag to keep track of empty nodata detection.
* @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);
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
int* empty_nodata_found);
#endif /* ITERATOR_ITER_RESPTYPE_H */

View File

@ -716,6 +716,56 @@ static int sanitize_nsec_is_overreach(sldns_buffer* pkt,
return 0;
}
/** Remove individual RRs, if the length is wrong. Returns true if the RRset
* has been removed. */
static int
scrub_sanitize_rr_length(sldns_buffer* pkt, struct msg_parse* msg,
struct rrset_parse* prev, struct rrset_parse** rrset, int* added_ede,
struct module_qstate* qstate)
{
struct rr_parse* rr, *rr_prev = NULL;
for(rr = (*rrset)->rr_first; rr; rr = rr->next) {
/* Sanity check for length of records
* An A record should be 6 bytes only
* (2 bytes for length and 4 for IPv4 addr)*/
if((*rrset)->type == LDNS_RR_TYPE_A && rr->size != 6 ) {
if(!*added_ede) {
*added_ede = 1;
errinf_ede(qstate, "sanitize: records of inappropriate length have been removed.",
LDNS_EDE_OTHER);
}
if(msgparse_rrset_remove_rr("sanitize: removing type A RR of inappropriate length:",
pkt, *rrset, rr_prev, rr, NULL, 0)) {
remove_rrset("sanitize: removing type A RRset of inappropriate length:",
pkt, msg, prev, rrset);
return 1;
}
continue;
}
/* Sanity check for length of records
* An AAAA record should be 18 bytes only
* (2 bytes for length and 16 for IPv6 addr)*/
if((*rrset)->type == LDNS_RR_TYPE_AAAA && rr->size != 18 ) {
if(!*added_ede) {
*added_ede = 1;
errinf_ede(qstate, "sanitize: records of inappropriate length have been removed.",
LDNS_EDE_OTHER);
}
if(msgparse_rrset_remove_rr("sanitize: removing type AAAA RR of inappropriate length:",
pkt, *rrset, rr_prev, rr, NULL, 0)) {
remove_rrset("sanitize: removing type AAAA RRset of inappropriate length:",
pkt, msg, prev, rrset);
return 1;
}
continue;
}
rr_prev = rr;
}
return 0;
}
/**
* Given a response event, remove suspect RRsets from the response.
* "Suspect" rrsets are potentially poison. Note that this routine expects
@ -728,15 +778,17 @@ static int sanitize_nsec_is_overreach(sldns_buffer* pkt,
* @param zonename: name of server zone.
* @param env: module environment with config and cache.
* @param ie: iterator environment with private address data.
* @param qstate: for setting errinf for EDE error messages.
* @return 0 on error.
*/
static int
scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, uint8_t* zonename, struct module_env* env,
struct iter_env* ie)
struct iter_env* ie, struct module_qstate* qstate)
{
int del_addi = 0; /* if additional-holding rrsets are deleted, we
do not trust the normalized additional-A-AAAA any more */
int added_rrlen_ede = 0;
struct rrset_parse* rrset, *prev;
prev = NULL;
rrset = msg->rrset_first;
@ -781,6 +833,14 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
rrset = msg->rrset_first;
while(rrset) {
/* Sanity check for length of records */
if(rrset->type == LDNS_RR_TYPE_A ||
rrset->type == LDNS_RR_TYPE_AAAA) {
if(scrub_sanitize_rr_length(pkt, msg, prev, &rrset,
&added_rrlen_ede, qstate))
continue;
}
/* remove private addresses */
if( (rrset->type == LDNS_RR_TYPE_A ||
rrset->type == LDNS_RR_TYPE_AAAA)) {
@ -854,7 +914,8 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
int
scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, uint8_t* zonename, struct regional* region,
struct module_env* env, struct iter_env* ie)
struct module_env* env, struct module_qstate* qstate,
struct iter_env* ie)
{
/* basic sanity checks */
log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS,
@ -886,7 +947,7 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
if(!scrub_normalize(pkt, msg, qinfo, region, env))
return 0;
/* delete all out-of-zone information */
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie))
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate))
return 0;
return 1;
}

View File

@ -48,6 +48,7 @@ struct query_info;
struct regional;
struct module_env;
struct iter_env;
struct module_qstate;
/**
* Cleanup the passed dns message.
@ -59,11 +60,13 @@ struct iter_env;
* 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 qstate: for setting errinf for EDE error messages.
* @param ie: iterator module environment data.
* @return: false if the message is total waste. true if scrubbed with success.
*/
int scrub_message(struct sldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, uint8_t* zonename, struct regional* regional,
struct module_env* env, struct iter_env* ie);
struct module_env* env, struct module_qstate* qstate,
struct iter_env* ie);
#endif /* ITERATOR_ITER_SCRUB_H */

View File

@ -2940,7 +2940,7 @@ static int
processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
struct iter_env* ie, int id)
{
int dnsseclame = 0, origtypecname = 0;
int dnsseclame = 0, origtypecname = 0, orig_empty_nodata_found;
enum response_type type;
iq->num_current_queries--;
@ -2960,12 +2960,25 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
return next_state(iq, QUERYTARGETS_STATE);
}
iq->timeout_count = 0;
orig_empty_nodata_found = iq->empty_nodata_found;
type = response_type_from_server(
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
iq->response, &iq->qinfo_out, iq->dp);
iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found);
iq->chase_to_rd = 0;
/* remove TC flag, if this is erroneously set by TCP upstream */
iq->response->rep->flags &= ~BIT_TC;
if(orig_empty_nodata_found != iq->empty_nodata_found &&
iq->empty_nodata_found < EMPTY_NODATA_RETRY_COUNT) {
/* try to search at another server */
if(qstate->reply) {
struct delegpt_addr* a = delegpt_find_addr(
iq->dp, &qstate->reply->remote_addr,
qstate->reply->remote_addrlen);
/* make selection disprefer it */
if(a) a->lame = 1;
}
return next_state(iq, QUERYTARGETS_STATE);
}
if(type == RESPONSE_TYPE_REFERRAL && (iq->chase_flags&BIT_RD) &&
!iq->auth_zone_response) {
/* When forwarding (RD bit is set), we handle referrals
@ -3501,7 +3514,7 @@ processPrimeResponse(struct module_qstate* qstate, int id)
iq->response->rep->flags &= ~(BIT_RD|BIT_RA); /* ignore rec-lame */
type = response_type_from_server(
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
iq->response, &iq->qchase, iq->dp);
iq->response, &iq->qchase, iq->dp, NULL);
if(type == RESPONSE_TYPE_ANSWER) {
qstate->return_rcode = LDNS_RCODE_NOERROR;
qstate->return_msg = iq->response;
@ -3874,6 +3887,23 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
/* explicitly set the EDE string to NULL */
iq->response->rep->reason_bogus_str = NULL;
if((qstate->env->cfg->val_log_level >= 2 ||
qstate->env->cfg->log_servfail) && qstate->errinf &&
!qstate->env->cfg->val_log_squelch) {
char* err_str = errinf_to_str_misc(qstate);
if(err_str) {
size_t err_str_len = strlen(err_str);
verbose(VERB_ALGO, "iterator EDE: %s", err_str);
/* allocate space and store the error
* string */
iq->response->rep->reason_bogus_str = regional_alloc(
qstate->region,
sizeof(char) * (err_str_len+1));
memcpy(iq->response->rep->reason_bogus_str,
err_str, err_str_len+1);
}
free(err_str);
}
/* we have finished processing this query */
qstate->ext_state[id] = module_finished;
@ -4098,7 +4128,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
/* normalize and sanitize: easy to delete items from linked lists */
if(!scrub_message(pkt, prs, &iq->qinfo_out, iq->dp->name,
qstate->env->scratch, qstate->env, ie)) {
qstate->env->scratch, qstate->env, qstate, ie)) {
/* if 0x20 enabled, start fallback, but we have no message */
if(event == module_event_capsfail && !iq->caps_fallback) {
iq->caps_fallback = 1;

View File

@ -101,6 +101,8 @@ extern int BLACKLIST_PENALTY;
* 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
/** Number of retries for empty nodata packets before it is accepted. */
#define EMPTY_NODATA_RETRY_COUNT 2
/**
* Global state for the iterator.
@ -415,6 +417,11 @@ struct iter_qstate {
*/
int refetch_glue;
/**
* This flag detects that a completely empty nodata was received,
* already so that it is accepted later. */
int empty_nodata_found;
/** list of pending queries to authoritative servers. */
struct outbound_list outlist;

View File

@ -62,6 +62,7 @@
#include "util/random.h"
#include "util/config_file.h"
#include "util/netevent.h"
#include "util/proxy_protocol.h"
#include "util/storage/lookup3.h"
#include "util/storage/slabhash.h"
#include "util/net_help.h"
@ -168,6 +169,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
hints_delete(w->env->hints);
w->env->hints = NULL;
}
#ifdef HAVE_SSL
w->sslctx = connect_sslctx_create(NULL, NULL,
cfg->tls_cert_bundle, cfg->tls_win_cert);
if(!w->sslctx) {
@ -175,6 +177,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
hints_delete(w->env->hints);
w->env->hints = NULL;
}
#endif
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);
}
@ -263,6 +266,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
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);
pp_init(&sldns_write_uint16, &sldns_write_uint32);
return w;
}

View File

@ -863,6 +863,9 @@ Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
%inline %{
//SWIG will see the ub_ctx as a class
struct ub_ctx {
/* Dummy member, so the struct is not empty, MSVC complains about
* that. */
int dummy;
};
%}

View File

@ -33,7 +33,12 @@
POSSIBILITY OF SUCH DAMAGE.
'''
def init(id, cfg):
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, cfg.python_script))
scripts=[]
s = cfg.python_script
while s != None:
scripts.append(s.str)
s = s.next
log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, scripts))
return True
def deinit(id):
@ -55,12 +60,15 @@ def setTTL(qstate, ttl):
def dataHex(data, prefix=""):
res = ""
for i in range(0, (len(data)+15)/16):
for i in range(0, int((len(data)+15)/16)):
res += "%s0x%02X | " % (prefix, i*16)
d = map(lambda x:ord(x), data[i*16:i*16+17])
if type(data[0]) == type(1):
d = map(lambda x:int(x), data[i*16:i*16+17])
else:
d = map(lambda x:ord(x), data[i*16:i*16+17])
for ch in d:
res += "%02X " % ch
for i in range(0,17-len(d)):
for i in range(0,17-len(data[i*16:i*16+17])):
res += " "
res += "| "
for ch in d:
@ -72,31 +80,31 @@ def dataHex(data, prefix=""):
return res
def printReturnMsg(qstate):
print "Return MSG rep :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (qstate.return_msg.rep.flags, qstate.return_msg.rep.qdcount,qstate.return_msg.rep.security, qstate.return_msg.rep.ttl)
print " qinfo :: qname:",qstate.return_msg.qinfo.qname_list, qstate.return_msg.qinfo.qname_str, "type:",qstate.return_msg.qinfo.qtype_str, "class:",qstate.return_msg.qinfo.qclass_str
print("Return MSG rep :: flags: %04X, QDcount: %d, Security:%d, TTL=%d" % (qstate.return_msg.rep.flags, qstate.return_msg.rep.qdcount,qstate.return_msg.rep.security, qstate.return_msg.rep.ttl))
print(" qinfo :: qname:",qstate.return_msg.qinfo.qname_list, qstate.return_msg.qinfo.qname_str, "type:",qstate.return_msg.qinfo.qtype_str, "class:",qstate.return_msg.qinfo.qclass_str)
if (qstate.return_msg.rep):
print "RRSets:",qstate.return_msg.rep.rrset_count
print("RRSets:",qstate.return_msg.rep.rrset_count)
prevkey = None
for i in range(0,qstate.return_msg.rep.rrset_count):
r = qstate.return_msg.rep.rrsets[i]
rk = r.rk
print i,":",rk.dname_list, rk.dname_str, "flags: %04X" % rk.flags,
print "type:",rk.type_str,"(%d)" % ntohs(rk.type), "class:",rk.rrset_class_str,"(%d)" % ntohs(rk.rrset_class)
print(i,":",rk.dname_list, rk.dname_str, "flags: %04X" % rk.flags)
print("type:",rk.type_str,"(%d)" % ntohs(rk.type), "class:",rk.rrset_class_str,"(%d)" % ntohs(rk.rrset_class))
d = r.entry.data
print " RRDatas:",d.count+d.rrsig_count
print(" RRDatas:",d.count+d.rrsig_count)
for j in range(0,d.count+d.rrsig_count):
print " ",j,":","TTL=",d.rr_ttl[j],"RR data:"
print dataHex(d.rr_data[j]," ")
print(" ",j,":","TTL=",d.rr_ttl[j],"RR data:")
print(dataHex(d.rr_data[j]," "))
def operate(id, event, qstate, qdata):
log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
#print "pythonmod: per query data", qdata
#print("pythonmod: per query data", qdata)
print "Query:", ''.join(map(lambda x:chr(max(32,ord(x))),qstate.qinfo.qname)), qstate.qinfo.qname_list,
print "Type:",qstate.qinfo.qtype_str,"(%d)" % qstate.qinfo.qtype,
print "Class:",qstate.qinfo.qclass_str,"(%d)" % qstate.qinfo.qclass
print
print("Query:", qstate.qinfo.qname, qstate.qinfo.qname_list, qstate.qinfo.qname_str)
print("Type:",qstate.qinfo.qtype_str,"(%d)" % qstate.qinfo.qtype)
print("Class:",qstate.qinfo.qclass_str,"(%d)" % qstate.qinfo.qclass)
print("")
# TEST:
# > dig @127.0.0.1 www.seznam.cz A
@ -118,7 +126,7 @@ def operate(id, event, qstate, qdata):
invalidateQueryInCache(qstate, qstate.return_msg.qinfo)
if (qstate.return_msg.rep.authoritative):
print "X"*300
print("X"*300)
setTTL(qstate, 10) #do cache nastavime TTL na 10
if not storeQueryInCache(qstate, qstate.return_msg.qinfo, qstate.return_msg.rep, 0):

View File

@ -2475,6 +2475,7 @@ az_find_ce(struct auth_zone* z, struct query_info* qinfo,
struct auth_rrset** rrset)
{
struct auth_data* n = node;
struct auth_rrset* lookrrset;
*ce = NULL;
*rrset = NULL;
if(!node_exact) {
@ -2497,21 +2498,23 @@ az_find_ce(struct auth_zone* z, struct query_info* qinfo,
/* see if the current candidate has issues */
/* not zone apex and has type NS */
if(n->namelen != z->namelen &&
(*rrset=az_domain_rrset(n, LDNS_RR_TYPE_NS)) &&
(lookrrset=az_domain_rrset(n, LDNS_RR_TYPE_NS)) &&
/* delegate here, but DS at exact the dp has notype */
(qinfo->qtype != LDNS_RR_TYPE_DS ||
n->namelen != qinfo->qname_len)) {
/* referral */
/* this is ce and the lowernode is nonexisting */
*ce = n;
return 0;
*rrset = lookrrset;
node_exact = 0;
}
/* not equal to qname and has type DNAME */
if(n->namelen != qinfo->qname_len &&
(*rrset=az_domain_rrset(n, LDNS_RR_TYPE_DNAME))) {
(lookrrset=az_domain_rrset(n, LDNS_RR_TYPE_DNAME))) {
/* this is ce and the lowernode is nonexisting */
*ce = n;
return 0;
*rrset = lookrrset;
node_exact = 0;
}
if(*ce == NULL && !domain_has_only_nsec3(n)) {

View File

@ -1391,8 +1391,15 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
return 0;
}
}
if (sock_queue_timeout && !set_recvtimestamp(s)) {
log_warn("socket timestamping is not available");
if(udp_port_type == listen_type_udp && sock_queue_timeout)
udp_port_type = listen_type_udpancil;
if (sock_queue_timeout) {
if(!set_recvtimestamp(s)) {
log_warn("socket timestamping is not available");
} else {
if(udp_port_type == listen_type_udp)
udp_port_type = listen_type_udpancil;
}
}
if(!port_insert(list, s, udp_port_type, is_pp2, ub_sock)) {
sock_close(s);
@ -1583,9 +1590,13 @@ listen_create(struct comm_base* base, struct listen_port* ports,
}
} else if(ports->ftype == listen_type_udpancil ||
ports->ftype == listen_type_udpancil_dnscrypt) {
#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
cp = comm_point_create_udp_ancil(base, ports->fd,
front->udp_buff, ports->pp2_enabled, cb,
cb_arg, ports->socket);
#else
log_warn("This system does not support UDP ancilliary data.");
#endif
}
if(!cp) {
log_err("can't create commpoint");

View File

@ -1224,11 +1224,12 @@ static inline int
mesh_is_rpz_respip_tcponly_action(struct mesh_state const* m)
{
struct respip_action_info const* respip_info = m->s.respip_action_info;
return respip_info == NULL
return (respip_info == NULL
? 0
: (respip_info->rpz_used
&& !respip_info->rpz_disabled
&& respip_info->action == respip_truncate);
&& respip_info->action == respip_truncate))
|| m->s.tcp_required;
}
static inline int

View File

@ -550,7 +550,6 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
log_assert(&key_p.reuse != (struct reuse_tcp*)result);
log_assert(&key_p != ((struct reuse_tcp*)result)->pending);
}
/* not found, return null */
/* It is possible that we search for something before the first element
* in the tree. Replace a null pointer with the first element.
@ -560,6 +559,7 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
result = rbtree_first(&outnet->tcp_reuse);
}
/* not found, return null */
if(!result || result == RBTREE_NULL)
return NULL;

View File

@ -2162,7 +2162,7 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
case RPZ_TCP_ONLY_ACTION:
/* basically a passthru here but the tcp-only will be
* honored before the query gets sent. */
ms->respip_action_info->action = respip_truncate;
ms->tcp_required = 1;
ret = NULL;
break;
case RPZ_DROP_ACTION:
@ -2217,7 +2217,7 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
case RPZ_TCP_ONLY_ACTION:
/* basically a passthru here but the tcp-only will be
* honored before the query gets sent. */
ms->respip_action_info->action = respip_truncate;
ms->tcp_required = 1;
ret = NULL;
break;
case RPZ_DROP_ACTION:
@ -2428,7 +2428,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
case RPZ_TCP_ONLY_ACTION:
/* basically a passthru here but the tcp-only will be
* honored before the query gets sent. */
ms->respip_action_info->action = respip_truncate;
ms->tcp_required = 1;
ret = NULL;
break;
case RPZ_DROP_ACTION:

View File

@ -192,6 +192,7 @@ static sldns_lookup_table sldns_edns_options_data[] = {
{ 6, "DHU" },
{ 7, "N3U" },
{ 8, "edns-client-subnet" },
{ 10, "COOKIE" },
{ 11, "edns-tcp-keepalive"},
{ 12, "Padding" },
{ 15, "EDE"},
@ -199,6 +200,38 @@ static sldns_lookup_table sldns_edns_options_data[] = {
};
sldns_lookup_table* sldns_edns_options = sldns_edns_options_data;
/* From RFC8914 5.2 Table 3, the "Extended DNS Error Codes" registry. */
static sldns_lookup_table sldns_edns_ede_codes_data[] = {
{ LDNS_EDE_NONE, "None" },
{ LDNS_EDE_OTHER, "Other Error" },
{ LDNS_EDE_UNSUPPORTED_DNSKEY_ALG, "Unsupported DNSKEY Algorithm" },
{ LDNS_EDE_UNSUPPORTED_DS_DIGEST, "Unsupported DS Digest Type" },
{ LDNS_EDE_STALE_ANSWER, "Stale Answer" },
{ LDNS_EDE_FORGED_ANSWER, "Forged Answer" },
{ LDNS_EDE_DNSSEC_INDETERMINATE, "DNSSEC Indeterminate" },
{ LDNS_EDE_DNSSEC_BOGUS, "DNSSEC Bogus" },
{ LDNS_EDE_SIGNATURE_EXPIRED, "Signature Expired" },
{ LDNS_EDE_SIGNATURE_NOT_YET_VALID, "Signature Not Yet Valid" },
{ LDNS_EDE_DNSKEY_MISSING, "DNSKEY Missing" },
{ LDNS_EDE_RRSIGS_MISSING, "RRSIGs Missing" },
{ LDNS_EDE_NO_ZONE_KEY_BIT_SET, "No Zone Key Bit Set" },
{ LDNS_EDE_NSEC_MISSING, "NSEC Missing" },
{ LDNS_EDE_CACHED_ERROR, "Cached Error" },
{ LDNS_EDE_NOT_READY, "Not Ready" },
{ LDNS_EDE_BLOCKED, "Blocked" },
{ LDNS_EDE_CENSORED, "Censored" },
{ LDNS_EDE_FILTERED, "Filtered" },
{ LDNS_EDE_PROHIBITED, "Prohibited" },
{ LDNS_EDE_STALE_NXDOMAIN_ANSWER, "Stale NXDOMAIN Answer" },
{ LDNS_EDE_NOT_AUTHORITATIVE, "Not Authoritative" },
{ LDNS_EDE_NOT_SUPPORTED, "Not Supported" },
{ LDNS_EDE_NO_REACHABLE_AUTHORITY, "No Reachable Authority" },
{ LDNS_EDE_NETWORK_ERROR, "Network Error" },
{ LDNS_EDE_INVALID_DATA, "Invalid Data" },
{ 0, NULL}
};
sldns_lookup_table* sldns_edns_ede_codes = sldns_edns_ede_codes_data;
static sldns_lookup_table sldns_tsig_errors_data[] = {
{ LDNS_TSIG_ERROR_NOERROR, "NOERROR" },
{ LDNS_RCODE_FORMERR, "FORMERR" },
@ -2234,6 +2267,52 @@ static int sldns_wire2str_edns_keepalive_print(char** s, size_t* sl,
return w;
}
int sldns_wire2str_edns_ede_print(char** s, size_t* sl,
uint8_t* data, size_t len)
{
uint16_t ede_code;
int w = 0;
sldns_lookup_table *lt;
size_t i;
int printable;
if(len < 2) {
w += sldns_str_print(s, sl, "malformed ede ");
w += print_hex_buf(s, sl, data, len);
return w;
}
ede_code = sldns_read_uint16(data);
lt = sldns_lookup_by_id(sldns_edns_ede_codes, (int)ede_code);
if(lt && lt->name)
w += sldns_str_print(s, sl, "%s", lt->name);
else w += sldns_str_print(s, sl, "%d", (int)ede_code);
if(len == 2)
return w;
w += sldns_str_print(s, sl, " ");
/* If it looks like text, show it as text. */
printable=1;
for(i=2; i<len; i++) {
if(isprint((unsigned char)data[i]) || data[i] == '\t')
continue;
printable = 0;
break;
}
if(printable) {
w += sldns_str_print(s, sl, "\"");
for(i=2; i<len; i++) {
w += str_char_print(s, sl, data[i]);
}
w += sldns_str_print(s, sl, "\"");
} else {
w += print_hex_buf(s, sl, data+2, len-2);
}
return w;
}
int sldns_wire2str_edns_option_print(char** s, size_t* sl,
uint16_t option_code, uint8_t* optdata, size_t optlen)
{
@ -2268,6 +2347,9 @@ int sldns_wire2str_edns_option_print(char** s, size_t* sl,
case LDNS_EDNS_PADDING:
w += print_hex_buf(s, sl, optdata, optlen);
break;
case LDNS_EDNS_EDE:
w += sldns_wire2str_edns_ede_print(s, sl, optdata, optlen);
break;
default:
/* unknown option code */
w += print_hex_buf(s, sl, optdata, optlen);

View File

@ -36,6 +36,8 @@ extern struct sldns_struct_lookup_table* sldns_opcodes;
extern struct sldns_struct_lookup_table* sldns_edns_flags;
/** EDNS option codes */
extern struct sldns_struct_lookup_table* sldns_edns_options;
/** EDNS EDE codes */
extern struct sldns_struct_lookup_table* sldns_edns_ede_codes;
/** error string from wireparse */
extern struct sldns_struct_lookup_table* sldns_wireparse_errors;
/** tsig errors are the rcodes with extra (higher) values */
@ -1020,6 +1022,17 @@ int sldns_wire2str_edns_n3u_print(char** str, size_t* str_len,
int sldns_wire2str_edns_subnet_print(char** str, size_t* str_len,
uint8_t* option_data, size_t option_len);
/**
* Print EDNS EDE option data to string. User buffers, moves string pointers.
* @param str: string buffer.
* @param str_len: length of string buffer.
* @param option_data: buffer with EDNS option code data.
* @param option_len: length of the data for this option.
* @return number of characters (except null) needed to print.
*/
int sldns_wire2str_edns_ede_print(char** str, size_t* str_len,
uint8_t* option_data, size_t option_len);
/**
* Print an EDNS option as OPT: VALUE. User buffers, moves string pointers.
* @param str: string buffer.

View File

@ -61,6 +61,17 @@ Specify the server to send the queries to. If not specified localhost (127.0.0.1
.B \-d \fIsecs
Delay after the connection before sending query. This tests the timeout
on the other side, eg. if shorter the connection is closed.
.TP
.B \-p \fIclient
Use proxy protocol to send the query. Specify the ipaddr@portnr of the client
to include in PROXYv2.
.TP
.B IXFR=serial
Pass the type of the query as IXFR=N to send an IXFR query with serial N.
.TP
.B NOTIFY[=serial]
Pass the type of the query as NOTIFY[=N] to send a notify packet. The serial N
of the new zone can be included.
.SH "EXAMPLES"
.LP
Some examples of use.

View File

@ -79,6 +79,8 @@ static void usage(char* argv[])
printf("-d secs delay after connection before sending query\n");
printf("-s use ssl\n");
printf("-h this help text\n");
printf("IXFR=N for the type, sends ixfr query with serial N.\n");
printf("NOTIFY[=N] for the type, sends notify. Can set new zone serial N.\n");
exit(1);
}
@ -115,6 +117,29 @@ open_svr(const char* svr, int udp, struct sockaddr_storage* addr,
return fd;
}
/** Append a SOA record with serial number */
static void
write_soa_serial_to_buf(sldns_buffer* buf, struct query_info* qinfo,
uint32_t serial)
{
sldns_buffer_set_position(buf, sldns_buffer_limit(buf));
sldns_buffer_set_limit(buf, sldns_buffer_capacity(buf));
/* Write compressed reference to the query */
sldns_buffer_write_u16(buf, PTR_CREATE(LDNS_HEADER_SIZE));
sldns_buffer_write_u16(buf, LDNS_RR_TYPE_SOA);
sldns_buffer_write_u16(buf, qinfo->qclass);
sldns_buffer_write_u32(buf, 3600); /* TTL */
sldns_buffer_write_u16(buf, 1+1+4*5); /* rdatalen */
sldns_buffer_write_u8(buf, 0); /* primary "." */
sldns_buffer_write_u8(buf, 0); /* email "." */
sldns_buffer_write_u32(buf, serial); /* serial */
sldns_buffer_write_u32(buf, 0); /* refresh */
sldns_buffer_write_u32(buf, 0); /* retry */
sldns_buffer_write_u32(buf, 0); /* expire */
sldns_buffer_write_u32(buf, 0); /* minimum */
sldns_buffer_flip(buf);
}
/** write a query over the TCP fd */
static void
write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
@ -123,6 +148,8 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
{
struct query_info qinfo;
size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf);
int have_serial = 0, is_notify = 0;
uint32_t serial = 0;
/* qname */
qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
if(!qinfo.qname) {
@ -130,12 +157,27 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
exit(1);
}
/* qtype and qclass */
qinfo.qtype = sldns_get_rr_type_by_name(strtype);
if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) {
printf("cannot parse query type: '%s'\n", strtype);
exit(1);
/* qtype */
if(strncasecmp(strtype, "IXFR=", 5) == 0) {
serial = (uint32_t)atoi(strtype+5);
have_serial = 1;
qinfo.qtype = LDNS_RR_TYPE_IXFR;
} else if(strcasecmp(strtype, "NOTIFY") == 0) {
is_notify = 1;
qinfo.qtype = LDNS_RR_TYPE_SOA;
} else if(strncasecmp(strtype, "NOTIFY=", 7) == 0) {
serial = (uint32_t)atoi(strtype+7);
have_serial = 1;
is_notify = 1;
qinfo.qtype = LDNS_RR_TYPE_SOA;
} else {
qinfo.qtype = sldns_get_rr_type_by_name(strtype);
if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) {
printf("cannot parse query type: '%s'\n", strtype);
exit(1);
}
}
/* qclass */
qinfo.qclass = sldns_get_rr_class_by_name(strclass);
if(qinfo.qclass == 0 && strcmp(strclass, "CLASS0") != 0) {
printf("cannot parse query class: '%s'\n", strclass);
@ -150,6 +192,21 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
sldns_buffer_write_u16_at(buf, 0, id);
sldns_buffer_write_u16_at(buf, 2, BIT_RD);
if(have_serial && qinfo.qtype == LDNS_RR_TYPE_IXFR) {
/* Attach serial to SOA record in the authority section. */
write_soa_serial_to_buf(buf, &qinfo, serial);
LDNS_NSCOUNT_SET(sldns_buffer_begin(buf), 1);
}
if(is_notify) {
LDNS_OPCODE_SET(sldns_buffer_begin(buf), LDNS_PACKET_NOTIFY);
LDNS_RD_CLR(sldns_buffer_begin(buf));
LDNS_AA_SET(sldns_buffer_begin(buf));
if(have_serial) {
write_soa_serial_to_buf(buf, &qinfo, serial);
LDNS_ANCOUNT_SET(sldns_buffer_begin(buf), 1);
}
}
if(1) {
/* add EDNS DO */
struct edns_data edns;
@ -361,6 +418,7 @@ static int parse_pp2_client(const char* pp2_client, int udp,
sldns_buffer* proxy_buf)
{
struct sockaddr_storage pp2_addr;
size_t bytes_written;
socklen_t pp2_addrlen = 0;
memset(&pp2_addr, 0, sizeof(pp2_addr));
if(*pp2_client == 0) return 0;
@ -369,7 +427,9 @@ static int parse_pp2_client(const char* pp2_client, int udp,
exit(1);
}
sldns_buffer_clear(proxy_buf);
pp2_write_to_buf(proxy_buf, &pp2_addr, !udp);
bytes_written = pp2_write_to_buf(sldns_buffer_begin(proxy_buf),
sldns_buffer_remaining(proxy_buf), &pp2_addr, !udp);
sldns_buffer_set_position(proxy_buf, bytes_written);
sldns_buffer_flip(proxy_buf);
return 1;
}
@ -541,6 +601,8 @@ int main(int argc, char** argv)
break;
case 'p':
pp2_client = optarg;
pp_init(&sldns_write_uint16,
&sldns_write_uint32);
break;
case 'a':
onarrival = 1;

View File

@ -76,10 +76,18 @@ static const char* zone_example_com =
"out.example.com. 3600 IN CNAME www.example.com.\n"
"plan.example.com. 3600 IN CNAME nonexist.example.com.\n"
"redir.example.com. 3600 IN DNAME redir.example.org.\n"
"redir2.example.com. 3600 IN DNAME redir2.example.org.\n"
"obscured.redir2.example.com. 3600 IN A 10.0.0.12\n"
"under2.redir2.example.com. 3600 IN DNAME redir3.example.net.\n"
"doubleobscured.under2.redir2.example.com. 3600 IN A 10.0.0.13\n"
"sub.example.com. 3600 IN NS ns1.sub.example.com.\n"
"sub.example.com. 3600 IN NS ns2.sub.example.com.\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
"ns2.sub.example.com. 3600 IN AAAA 2001::7\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
"obscured.sub2.example.com. 3600 IN A 10.0.0.10\n"
"under.sub2.example.com. 3600 IN NS ns.under.sub2.example.com.\n"
"doubleobscured.under.sub2.example.com. 3600 IN A 10.0.0.11\n"
"*.wild.example.com. 3600 IN A 10.0.0.8\n"
"*.wild2.example.com. 3600 IN CNAME www.example.com.\n"
"*.wild3.example.com. 3600 IN A 10.0.0.8\n"
@ -281,6 +289,54 @@ static struct q_ans example_com_queries[] = {
"foo.abc.redir.example.com. 0 IN CNAME foo.abc.redir.example.org.\n"
},
{ "example.com", "redir2.example.com. DNAME", "",
";flags QR AA rcode NOERROR\n"
";answer section\n"
"redir2.example.com. 3600 IN DNAME redir2.example.org.\n"
},
{ "example.com", "abc.redir2.example.com. A", "",
";flags QR AA rcode NOERROR\n"
";answer section\n"
"redir2.example.com. 3600 IN DNAME redir2.example.org.\n"
"abc.redir2.example.com. 0 IN CNAME abc.redir2.example.org.\n"
},
{ "example.com", "obscured.redir2.example.com. A", "",
";flags QR AA rcode NOERROR\n"
";answer section\n"
"redir2.example.com. 3600 IN DNAME redir2.example.org.\n"
"obscured.redir2.example.com. 0 IN CNAME obscured.redir2.example.org.\n"
},
{ "example.com", "under2.redir2.example.com. A", "",
";flags QR AA rcode NOERROR\n"
";answer section\n"
"redir2.example.com. 3600 IN DNAME redir2.example.org.\n"
"under2.redir2.example.com. 0 IN CNAME under2.redir2.example.org.\n"
},
{ "example.com", "doubleobscured.under2.redir2.example.com. A", "",
";flags QR AA rcode NOERROR\n"
";answer section\n"
"redir2.example.com. 3600 IN DNAME redir2.example.org.\n"
"doubleobscured.under2.redir2.example.com. 0 IN CNAME doubleobscured.under2.redir2.example.org.\n"
},
{ "example.com", "foo.doubleobscured.under2.redir2.example.com. A", "",
";flags QR AA rcode NOERROR\n"
";answer section\n"
"redir2.example.com. 3600 IN DNAME redir2.example.org.\n"
"foo.doubleobscured.under2.redir2.example.com. 0 IN CNAME foo.doubleobscured.under2.redir2.example.org.\n"
},
{ "example.com", "foo.under2.redir2.example.com. A", "",
";flags QR AA rcode NOERROR\n"
";answer section\n"
"redir2.example.com. 3600 IN DNAME redir2.example.org.\n"
"foo.under2.redir2.example.com. 0 IN CNAME foo.under2.redir2.example.org.\n"
},
{ "example.com", "sub.example.com. NS", "",
";flags QR rcode NOERROR\n"
";authority section\n"
@ -357,6 +413,78 @@ static struct q_ans example_com_queries[] = {
"ns2.sub.example.com. 3600 IN AAAA 2001::7\n"
},
{ "example.com", "sub2.example.com. A", "",
";flags QR rcode NOERROR\n"
";authority section\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
";additional section\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
},
{ "example.com", "sub2.example.com. NS", "",
";flags QR rcode NOERROR\n"
";authority section\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
";additional section\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
},
{ "example.com", "obscured.sub2.example.com. A", "",
";flags QR rcode NOERROR\n"
";authority section\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
";additional section\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
},
{ "example.com", "abc.obscured.sub2.example.com. A", "",
";flags QR rcode NOERROR\n"
";authority section\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
";additional section\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
},
{ "example.com", "under.sub2.example.com. A", "",
";flags QR rcode NOERROR\n"
";authority section\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
";additional section\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
},
{ "example.com", "under.sub2.example.com. NS", "",
";flags QR rcode NOERROR\n"
";authority section\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
";additional section\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
},
{ "example.com", "abc.under.sub2.example.com. A", "",
";flags QR rcode NOERROR\n"
";authority section\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
";additional section\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
},
{ "example.com", "doubleobscured.under.sub2.example.com. A", "",
";flags QR rcode NOERROR\n"
";authority section\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
";additional section\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
},
{ "example.com", "abc.doubleobscured.under.sub2.example.com. A", "",
";flags QR rcode NOERROR\n"
";authority section\n"
"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n"
";additional section\n"
"ns1.sub.example.com. 3600 IN A 10.0.0.6\n"
},
{ "example.com", "wild.example.com. A", "",
";flags QR AA rcode NOERROR\n"
";authority section\n"

View File

@ -140,33 +140,6 @@ SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
broken.example.com. IN AAAA
SECTION ANSWER
; NO AAAA present
SECTION AUTHORITY
example.com. IN SOA a. b. 1 2 3 4 5
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
broken.example.com. IN A
SECTION ANSWER
broken.example.com. IN A 5.6.7.8
broken.example.com. IN A \# 3 030405
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
@ -284,25 +257,4 @@ SECTION AUTHORITY
7.6.5.in-addr.arpa. IN NS ns.example.com.
ENTRY_END
; synthesize from broken, malformed A records
STEP 80 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
broken.example.com. IN AAAA
ENTRY_END
; recursion happens here.
STEP 90 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
broken.example.com. IN AAAA
SECTION ANSWER
SECTION AUTHORITY
example.com. IN SOA a. b. 1 2 3 4 5
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END

View File

@ -78,6 +78,18 @@ example2.com. IN NS ns2.example2.com.
SECTION ADDITIONAL
ns2.example2.com. IN A 1.2.3.5
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
foo.com. IN NS
SECTION AUTHORITY
foo.com. IN NS ns.foo.com.
SECTION ADDITIONAL
ns.foo.com. IN A 1.2.3.5
ENTRY_END
RANGE_END
; ns.example.com.
@ -172,6 +184,27 @@ www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
ENTRY_END
; foo.com
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.foo.com. IN A
SECTION ANSWER
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
ns.foo.com. IN AAAA
SECTION ANSWER
SECTION AUTHORITY
;foo.com. IN SOA ns2.foo.com root.foo.com 4 14400 3600 604800 3600
ENTRY_END
RANGE_END
STEP 1 QUERY
@ -195,4 +228,21 @@ ENTRY_END
; wait for pending nameserver lookups.
STEP 20 TRAFFIC
; Test that a nodata stays a nodata.
STEP 30 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
www.foo.com. IN A
ENTRY_END
STEP 40 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
www.foo.com. IN A
SECTION ANSWER
ENTRY_END
SCENARIO_END

298
testdata/iter_scrub_rr_length.rpl vendored Normal file
View File

@ -0,0 +1,298 @@
; config options
server:
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: "no"
minimal-responses: no
rrset-roundrobin: no
ede: yes
log-servfail: yes
stub-zone:
name: "."
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
CONFIG_END
SCENARIO_BEGIN Test scrub of RRs of inappropriate length
; K.ROOT-SERVERS.NET.
RANGE_BEGIN 0 200
ADDRESS 193.0.14.129
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION AUTHORITY
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
RANGE_END
; a.gtld-servers.net.
RANGE_BEGIN 0 200
ADDRESS 192.5.6.30
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
com. IN NS
SECTION ANSWER
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
RANGE_END
; ns.example.com.
RANGE_BEGIN 0 200
ADDRESS 1.2.3.4
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.com. IN NS
SECTION ANSWER
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
www.example.com. IN A \# 3 030405
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.example.com. IN AAAA
SECTION ANSWER
www.example.com. IN AAAA 2001:db8::1234
www.example.com. IN AAAA \# 48 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
broken1.example.com. IN A
SECTION ANSWER
broken1.example.com. IN A \# 3 030405
broken1.example.com. IN A \# 3 030406
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
broken1.example.com. IN AAAA
SECTION ANSWER
broken1.example.com. IN AAAA \# 48 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F
broken1.example.com. IN AAAA \# 48 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E30
broken1.example.com. IN AAAA \# 48 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E31
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
broken2.example.com. IN A
SECTION ANSWER
broken2.example.com. IN A 1.2.3.4
broken2.example.com. IN A \# 3 030405
broken2.example.com. IN A 1.2.3.5
broken2.example.com. IN A \# 3 030406
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A \# 3 030407
ns.example.com. IN A 1.2.3.6
ns.example.com. IN A \# 3 030408
ns.example.com. IN A \# 3 030409
ns.example.com. IN A 1.2.3.7
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
STEP 20 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
www.example.com. IN AAAA
ENTRY_END
STEP 30 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
www.example.com. IN AAAA
SECTION ANSWER
www.example.com. IN AAAA 2001:db8::1234
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
STEP 40 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
broken1.example.com. IN A
ENTRY_END
STEP 50 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
broken1.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
STEP 60 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
broken1.example.com. IN AAAA
ENTRY_END
STEP 70 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
broken1.example.com. IN AAAA
SECTION ANSWER
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
STEP 80 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
broken2.example.com. IN A
ENTRY_END
STEP 90 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
broken2.example.com. IN A
SECTION ANSWER
broken2.example.com. IN A 1.2.3.4
broken2.example.com. IN A 1.2.3.5
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.6
ns.example.com. IN A 1.2.3.7
ENTRY_END
STEP 100 QUERY
ENTRY_BEGIN
REPLY RD CD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 110 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ede=0
REPLY QR RD CD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.6
ns.example.com. IN A 1.2.3.7
ENTRY_END
SCENARIO_END

View File

@ -0,0 +1,34 @@
server:
verbosity: 7
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
# for the test, so that DNSSEC verification works.
#val-override-date: 20230929090000
trust-anchor: ". DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D"
remote-control:
control-enable: yes
control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
control-use-cert: no
# for the test, an upstream server in the test setup.
stub-zone:
name: "."
stub-addr: 127.0.0.1@@TOPORT@
# hyperlocal root zone
auth-zone:
name: "."
fallback-enabled: yes
for-downstream: no
for-upstream: yes
zonefile: "root.zone"
zonemd-check: yes
zonemd-reject-absence: yes

View File

@ -0,0 +1,16 @@
BaseName: root_zonemd
Version: 1.0
Description: ZONEMD check for root zone
CreationDate: Fri 29 Sep 09:00:00 CEST 2023
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: root_zonemd.pre
Post: root_zonemd.post
Test: root_zonemd.test
AuxFiles:
Passed:
Failure:

View File

@ -0,0 +1,14 @@
# #-- root_zonemd.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
. ../common.sh
echo "> cat logfiles"
cat fwd.log
cat unbound.log
kill_pid $FWD_PID
kill_pid $UNBOUND_PID
rm -f $CONTROL_PATH/controlpipe.$CONTROL_PID

View File

@ -0,0 +1,50 @@
# #-- root_zonemd.pre--#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
. ../common.sh
# attempt to download the root zone
from=k.root-servers.net
dig @$from . AXFR > root.txt
if test $? -ne 0; then
echo "could not fetch root zone"
skip_test "could not fetch root zone"
fi
grep " SOA " root.txt | head -1 > root.soa
cat root.soa >> root.zone
grep -v " SOA " root.txt >> root.zone
echo "fetched root.zone"
ls -l root.zone
cat root.soa
get_random_port 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT root_zonemd.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
CONTROL_PATH=/tmp
CONTROL_PID=$$
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' -e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' -e 's/@CONTROL_PID@/'$CONTROL_PID'/' < root_zonemd.conf > ub.conf
# start unbound in the background
PRE="../.."
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
echo "CONTROL_PATH=$CONTROL_PATH" >> .tpkg.var.test
echo "CONTROL_PID=$CONTROL_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log

View File

@ -0,0 +1,51 @@
# #-- root_zonemd.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
# do the test
echo "> dig www.example.com."
dig @localhost -p $UNBOUND_PORT . SOA | tee outfile
echo "> check answer"
if grep root-servers outfile | grep "nstld.verisign-grs.com"; then
echo "OK"
else
echo "Not OK"
exit 1
fi
echo "> unbound-control status"
$PRE/unbound-control -c ub.conf status
if test $? -ne 0; then
echo "wrong exit value."
exit 1
else
echo "exit value: OK"
fi
# This is the output when an unsupported algorithm is used.
if grep "auth zone . ZONEMD unsupported algorithm" unbound.log; then
echo "OK"
else
echo "ZONEMD verification not OK"
exit 1
fi
echo "> unbound-control auth_zone_reload ."
$PRE/unbound-control -c ub.conf auth_zone_reload . 2>&1 | tee outfile
if test $? -ne 0; then
echo "wrong exit value."
exit 1
fi
# The output of the reload can be checked.
#echo "> check unbound-control output"
#if grep "example.com: ZONEMD verification successful" outfile; then
#echo "OK"
#else
#echo "Not OK"
#exit 1
#fi
exit 0

View File

@ -0,0 +1,9 @@
# reply to everything
ENTRY_BEGIN
MATCH opcode
ADJUST copy_id copy_query
REPLY QR SERVFAIL
SECTION QUESTION
example.com. IN SOA
SECTION ANSWER
ENTRY_END

View File

@ -225,6 +225,36 @@ ENTRY_END
RANGE_END
; dd. ------------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 8.8.3.8
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
dd. IN NS
SECTION ANSWER
dd. IN NS ns1.dd.
SECTION ADDITIONAL
ns1.dd. IN A 8.8.3.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
gotham.dd. IN A
SECTION AUTHORITY
gotham.dd. IN NS ns1.gotham.dd.
SECTION ADDITIONAL
ns1.gotham.dd. IN A 192.0.3.1
ENTRY_END
RANGE_END
; ff. ------------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 8.8.6.8
@ -303,6 +333,22 @@ ENTRY_END
RANGE_END
; ns1.gotham.dd. -------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 192.0.3.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
gotham.dd. IN A
SECTION ANSWER
gotham.dd. IN A 192.0.3.2
ENTRY_END
RANGE_END
; ns1.gotham.ff. -------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 192.0.5.1
@ -387,4 +433,39 @@ SECTION ANSWER
gotham.ff. IN A 127.0.0.1
ENTRY_END
STEP 40 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
gotham.dd. IN A
ENTRY_END
; should come back truncated because TCP is required.
STEP 41 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA TC NOERROR
SECTION QUESTION
gotham.dd. IN A
SECTION ANSWER
ENTRY_END
STEP 42 QUERY
ENTRY_BEGIN
MATCH TCP
REPLY RD
SECTION QUESTION
gotham.dd. IN A
ENTRY_END
STEP 43 CHECK_ANSWER
ENTRY_BEGIN
MATCH all TCP
REPLY QR RD RA NOERROR
SECTION QUESTION
gotham.dd. IN A
SECTION ANSWER
gotham.dd. IN A 192.0.3.2
ENTRY_END
SCENARIO_END

155
testdata/subnet_prezero.crpl vendored Normal file
View File

@ -0,0 +1,155 @@
; subnet unit test
server:
trust-anchor-signaling: no
send-client-subnet: 1.2.3.4
send-client-subnet: 1.2.3.5
target-fetch-policy: "0 0 0 0 0"
module-config: "subnetcache validator iterator"
qname-minimisation: no
minimal-responses: no
stub-zone:
name: "example.com"
stub-addr: 1.2.3.4
CONFIG_END
SCENARIO_BEGIN Test subnetcache source prefix zero from client.
; In RFC7871 section-7.1.2 (para. 2).
; It says that the recursor must send no EDNS subnet or its own address
; in the EDNS subnet to the upstream server. And use that answer for the
; source prefix length zero query. That type of query is for privacy.
; The authority server is then going to use the resolver's IP, if any, to
; tailor the answer to the query source address.
; ns.example.com
RANGE_BEGIN 0 100
ADDRESS 1.2.3.4
; reply with 0.0.0.0/0 in reply
; For the test the answers for 0.0.0.0/0 queries are SERVFAIL, the normal
; answers are NOERROR.
ENTRY_BEGIN
MATCH opcode qtype qname ednsdata
ADJUST copy_id
REPLY QR AA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN CNAME star.c10r.example.com.
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
00 08 00 04 ; OPCODE=subnet, optlen
00 01 00 00 ; ip4, scope 0, source 0
; 0.0.0.0/0
HEX_EDNSDATA_END
ENTRY_END
; reply without subnet
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN CNAME star.c10r.example.com.
ENTRY_END
; delegation answer for c10r.example.com, with subnet /0
ENTRY_BEGIN
MATCH opcode subdomain ednsdata
ADJUST copy_id copy_query
REPLY QR DO SERVFAIL
SECTION QUESTION
c10r.example.com. IN NS
SECTION AUTHORITY
c10r.example.com. IN NS ns.c10r.example.com.
SECTION ADDITIONAL
ns.c10r.example.com. IN A 1.2.3.5
HEX_EDNSDATA_BEGIN
00 08 00 04 ; OPCODE=subnet, optlen
00 01 00 00 ; ip4, scope 0, source 0
; 0.0.0.0/0
HEX_EDNSDATA_END
ENTRY_END
; delegation answer for c10r.example.com, without subnet
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR DO NOERROR
SECTION QUESTION
c10r.example.com. IN NS
SECTION AUTHORITY
c10r.example.com. IN NS ns.c10r.example.com.
SECTION ADDITIONAL
ns.c10r.example.com. IN A 1.2.3.5
ENTRY_END
RANGE_END
; ns.c10r.example.com
RANGE_BEGIN 0 100
ADDRESS 1.2.3.5
; reply with 0.0.0.0/0 in reply
ENTRY_BEGIN
MATCH opcode qtype qname ednsdata
ADJUST copy_id
REPLY QR AA DO SERVFAIL
SECTION QUESTION
star.c10r.example.com. IN A
SECTION ANSWER
star.c10r.example.com. IN A 1.2.3.6
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
00 08 00 04 ; OPCODE=subnet, optlen
00 01 00 00 ; ip4, scope 0, source 0
; 0.0.0.0/0
HEX_EDNSDATA_END
ENTRY_END
; reply without subnet
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA DO NOERROR
SECTION QUESTION
star.c10r.example.com. IN A
SECTION ANSWER
star.c10r.example.com. IN A 1.2.3.6
ENTRY_END
RANGE_END
; ask for www.example.com
; server answers with CNAME to a delegation, that then
; returns a /24 answer.
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
www.example.com. IN A
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
00 08 00 04 ; OPCODE=subnet, optlen
00 01 00 00 ; ip4, scope 0, source 0
; 0.0.0.0/0
HEX_EDNSDATA_END
ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ednsdata
REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN CNAME star.c10r.example.com.
star.c10r.example.com. IN A 1.2.3.6
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
00 08 00 04 ; OPCODE=subnet, optlen
00 01 00 00 ; ip4, scope 0, source 0
; 0.0.0.0/0
HEX_EDNSDATA_END
ENTRY_END
SCENARIO_END

164
testdata/val_scrub_rr_length.rpl vendored Normal file
View File

@ -0,0 +1,164 @@
; config options
; The island of trust is at example.com
server:
trust-anchor: "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: "no"
trust-anchor-signaling: no
minimal-responses: no
rrset-roundrobin: no
ede: yes
log-servfail: yes
stub-zone:
name: "."
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
CONFIG_END
SCENARIO_BEGIN Test validator with scrub of RR for inappropriate length
; K.ROOT-SERVERS.NET.
RANGE_BEGIN 0 100
ADDRESS 193.0.14.129
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION AUTHORITY
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
RANGE_END
; a.gtld-servers.net.
RANGE_BEGIN 0 100
ADDRESS 192.5.6.30
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
com. IN NS
SECTION ANSWER
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
RANGE_END
; ns.example.com.
RANGE_BEGIN 0 100
ADDRESS 1.2.3.4
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.com. IN NS
SECTION ANSWER
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 8 2 3600 20070926134150 20070829134150 55566 example.com. cHdLVCzujUQs6b67c1SmCX+/br4tgOg86Gj/R/x+PKUQmWHyeVwBSTlJuLOHbca3CQoyIQc+V2ilK6fjwjbY/dLk4uOlux8L+Zn7HsUXSOwJPIjsM3LuTa8CYDMvYhOP7KGR+vNpJVSsQ25pyDn6Rzsdl3E7DAf7uSkPV8VJwa8=
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 8 3 3600 20070926134150 20070829134150 55566 example.com. PBwNifMNxTXlDorHX1neq1wUhWLmqk+PZ+PBZCI5BJAmakdgOXdLQiVqlKaErJyA/4uN+99fUf6/DqxwgxL8FIPdBkxMOTJaKrCFjEhL6qozTd3+DI6qFJPgTm1lrkpvb9W72MtK2vxAyT5I/bG2SWKdpzOaQXysbDb2hnxq3as=
ENTRY_END
; response to DNSKEY priming query
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.com. IN DNSKEY
SECTION ANSWER
example.com. IN DNSKEY 256 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55566 (zsk), size = 1024b}
example.com. 3600 IN RRSIG DNSKEY 8 2 3600 20070926134150 20070829134150 55566 example.com. Ni7Q17l2dzKcAnHdU3Mycpdwo0I6qgGxRvBhBNI43xIUFHJpgKpbeMFxKvVTkbwHyMPMIuHmOaC82IBhOpGD10SExVh4erQhWS3Hvl+m4Cwl3WI9N+AW6CTB9yj+d4xzX3bHjjBt6MSk4bU8ABR7qIoAjgjY7zdtUDWQlaM+d18=
SECTION AUTHORITY
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 8 2 3600 20070926134150 20070829134150 55566 example.com. cHdLVCzujUQs6b67c1SmCX+/br4tgOg86Gj/R/x+PKUQmWHyeVwBSTlJuLOHbca3CQoyIQc+V2ilK6fjwjbY/dLk4uOlux8L+Zn7HsUXSOwJPIjsM3LuTa8CYDMvYhOP7KGR+vNpJVSsQ25pyDn6Rzsdl3E7DAf7uSkPV8VJwa8=
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 8 3 3600 20070926134150 20070829134150 55566 example.com. PBwNifMNxTXlDorHX1neq1wUhWLmqk+PZ+PBZCI5BJAmakdgOXdLQiVqlKaErJyA/4uN+99fUf6/DqxwgxL8FIPdBkxMOTJaKrCFjEhL6qozTd3+DI6qFJPgTm1lrkpvb9W72MtK2vxAyT5I/bG2SWKdpzOaQXysbDb2hnxq3as=
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
ns.example.com. IN AAAA
SECTION AUTHORITY
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 8 2 3600 20070926134150 20070829134150 55566 example.com. cHdLVCzujUQs6b67c1SmCX+/br4tgOg86Gj/R/x+PKUQmWHyeVwBSTlJuLOHbca3CQoyIQc+V2ilK6fjwjbY/dLk4uOlux8L+Zn7HsUXSOwJPIjsM3LuTa8CYDMvYhOP7KGR+vNpJVSsQ25pyDn6Rzsdl3E7DAf7uSkPV8VJwa8=
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 8 3 3600 20070926134150 20070829134150 55566 example.com. PBwNifMNxTXlDorHX1neq1wUhWLmqk+PZ+PBZCI5BJAmakdgOXdLQiVqlKaErJyA/4uN+99fUf6/DqxwgxL8FIPdBkxMOTJaKrCFjEhL6qozTd3+DI6qFJPgTm1lrkpvb9W72MtK2vxAyT5I/bG2SWKdpzOaQXysbDb2hnxq3as=
ENTRY_END
; response to query of interest
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
www.example.com. IN A \# 5 0102030405
; RRSIG includes the malformed record.
www.example.com. 3600 IN RRSIG A 8 3 3600 20070926134150 20070829134150 55566 example.com. W4WFu9B81uRvp3Dj8uLIscypznKWuLuKrZqVg1on5/45/3/xyjHvj3TjTL3gruWFXPiQpldvOstXLZ5eN3OpqILdkVey0eqVATujpHwIruY6GWztVx5WptmFfK6E6zzshZ3RmAARqq/czQ+IZli2A9xixdY2H0o1dSU6gohEjjE=
SECTION AUTHORITY
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 8 2 3600 20070926134150 20070829134150 55566 example.com. cHdLVCzujUQs6b67c1SmCX+/br4tgOg86Gj/R/x+PKUQmWHyeVwBSTlJuLOHbca3CQoyIQc+V2ilK6fjwjbY/dLk4uOlux8L+Zn7HsUXSOwJPIjsM3LuTa8CYDMvYhOP7KGR+vNpJVSsQ25pyDn6Rzsdl3E7DAf7uSkPV8VJwa8=
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ns.example.com. 3600 IN RRSIG A 8 3 3600 20070926134150 20070829134150 55566 example.com. PBwNifMNxTXlDorHX1neq1wUhWLmqk+PZ+PBZCI5BJAmakdgOXdLQiVqlKaErJyA/4uN+99fUf6/DqxwgxL8FIPdBkxMOTJaKrCFjEhL6qozTd3+DI6qFJPgTm1lrkpvb9W72MtK2vxAyT5I/bG2SWKdpzOaQXysbDb2hnxq3as=
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ede=0
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
ENTRY_END
SCENARIO_END

View File

@ -390,6 +390,7 @@ config_create(void)
cfg->redis_timeout = 100;
cfg->redis_server_port = 6379;
cfg->redis_expire_records = 0;
cfg->redis_logical_db = 0;
#endif /* USE_REDIS */
#endif /* USE_CACHEDB */
#ifdef USE_IPSET
@ -1319,6 +1320,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_STR(opt, "redis-server-password", redis_server_password)
else O_DEC(opt, "redis-timeout", redis_timeout)
else O_YNO(opt, "redis-expire-records", redis_expire_records)
else O_DEC(opt, "redis-logical-db", redis_logical_db)
#endif /* USE_REDIS */
#endif /* USE_CACHEDB */
#ifdef USE_IPSET

View File

@ -717,6 +717,8 @@ struct config_file {
int redis_timeout;
/** set timeout on redis records based on DNS response ttl */
int redis_expire_records;
/** set the redis logical database upon connection */
int redis_logical_db;
#endif
#endif
/** Downstream DNS Cookies */

View File

@ -565,6 +565,7 @@ redis-server-path{COLON} { YDVAR(1, VAR_CACHEDB_REDISPATH) }
redis-server-password{COLON} { YDVAR(1, VAR_CACHEDB_REDISPASSWORD) }
redis-timeout{COLON} { YDVAR(1, VAR_CACHEDB_REDISTIMEOUT) }
redis-expire-records{COLON} { YDVAR(1, VAR_CACHEDB_REDISEXPIRERECORDS) }
redis-logical-db{COLON} { YDVAR(1, VAR_CACHEDB_REDISLOGICALDB) }
ipset{COLON} { YDVAR(0, VAR_IPSET) }
name-v4{COLON} { YDVAR(1, VAR_IPSET_NAME_V4) }
name-v6{COLON} { YDVAR(1, VAR_IPSET_NAME_V6) }

View File

@ -179,6 +179,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_CACHEDB VAR_CACHEDB_BACKEND VAR_CACHEDB_SECRETSEED
%token VAR_CACHEDB_REDISHOST VAR_CACHEDB_REDISPORT VAR_CACHEDB_REDISTIMEOUT
%token VAR_CACHEDB_REDISEXPIRERECORDS VAR_CACHEDB_REDISPATH VAR_CACHEDB_REDISPASSWORD
%token VAR_CACHEDB_REDISLOGICALDB
%token VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM VAR_FOR_UPSTREAM
%token VAR_AUTH_ZONE VAR_ZONEFILE VAR_MASTER VAR_URL VAR_FOR_DOWNSTREAM
%token VAR_FALLBACK_ENABLED VAR_TLS_ADDITIONAL_PORT VAR_LOW_RTT VAR_LOW_RTT_PERMIL
@ -3716,7 +3717,8 @@ contents_cachedb: contents_cachedb content_cachedb
| ;
content_cachedb: cachedb_backend_name | cachedb_secret_seed |
redis_server_host | redis_server_port | redis_timeout |
redis_expire_records | redis_server_path | redis_server_password
redis_expire_records | redis_server_path | redis_server_password |
redis_logical_db
;
cachedb_backend_name: VAR_CACHEDB_BACKEND STRING_ARG
{
@ -3819,6 +3821,21 @@ redis_expire_records: VAR_CACHEDB_REDISEXPIRERECORDS STRING_ARG
free($2);
}
;
redis_logical_db: VAR_CACHEDB_REDISLOGICALDB STRING_ARG
{
#if defined(USE_CACHEDB) && defined(USE_REDIS)
int db;
OUTYY(("P(redis_logical_db:%s)\n", $2));
db = atoi($2);
if((db == 0 && strcmp($2, "0") != 0) || db < 0)
yyerror("valid redis logical database index expected");
else cfg_parser->cfg->redis_logical_db = db;
#else
OUTYY(("P(Compiled without cachedb or redis, ignoring)\n"));
#endif
free($2);
}
;
server_tcp_connection_limit: VAR_TCP_CONNECTION_LIMIT STRING_ARG STRING_ARG
{
OUTYY(("P(server_tcp_connection_limit:%s %s)\n", $2, $3));

View File

@ -47,6 +47,7 @@
#include "util/regional.h"
#include "util/rfc_1982.h"
#include "util/edns.h"
#include "util/net_help.h"
#include "sldns/rrdef.h"
#include "sldns/sbuffer.h"
#include "sldns/parseutil.h"
@ -1306,3 +1307,27 @@ log_edns_opt_list(enum verbosity_value level, const char* info_str,
}
}
/** remove RR from msgparse RRset, return true if rrset is entirely bad */
int
msgparse_rrset_remove_rr(const char* str, sldns_buffer* pkt, struct rrset_parse* rrset,
struct rr_parse* prev, struct rr_parse* rr, struct sockaddr_storage* addr, socklen_t addrlen)
{
if(verbosity >= VERB_QUERY && rrset->dname_len <= LDNS_MAX_DOMAINLEN && str) {
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
dname_pkt_copy(pkt, buf, rrset->dname);
if(addr)
log_name_addr(VERB_QUERY, str, buf, addr, addrlen);
else log_nametypeclass(VERB_QUERY, str, buf,
rrset->type, ntohs(rrset->rrset_class));
}
if(prev)
prev->next = rr->next;
else rrset->rr_first = rr->next;
if(rrset->rr_last == rr)
rrset->rr_last = prev;
rrset->rr_count --;
rrset->size -= rr->size;
/* rr struct still exists, but is unlinked, so that in the for loop
* the rr->next works fine to continue. */
return rrset->rr_count == 0;
}

View File

@ -371,4 +371,22 @@ void msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset);
void log_edns_opt_list(enum verbosity_value level, const char* info_str,
struct edns_option* list);
/**
* Remove RR from msgparse RRset.
* @param str: this string is used for logging if verbose. If NULL, there is
* no logging of the remove.
* @param pkt: packet in buffer that is removed from. Used to log the name
* of the item removed.
* @param rrset: RRset that the RR is removed from.
* @param prev: previous RR in list, or NULL.
* @param rr: RR that is removed.
* @param addr: address used for logging, if verbose, or NULL then it is not
* used.
* @param addrlen: length of addr, if that is not NULL.
* @return true if rrset is entirely bad, it would then need to be removed.
*/
int msgparse_rrset_remove_rr(const char* str, struct sldns_buffer* pkt,
struct rrset_parse* rrset, struct rr_parse* prev, struct rr_parse* rr,
struct sockaddr_storage* addr, socklen_t addrlen);
#endif /* UTIL_DATA_MSGPARSE_H */

View File

@ -172,7 +172,9 @@ int
fptr_whitelist_event(void (*fptr)(int, short, void *))
{
if(fptr == &comm_point_udp_callback) return 1;
#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
else if(fptr == &comm_point_udp_ancil_callback) return 1;
#endif
else if(fptr == &comm_point_tcp_accept_callback) return 1;
else if(fptr == &comm_point_tcp_handle_callback) return 1;
else if(fptr == &comm_timer_callback) return 1;

View File

@ -194,6 +194,24 @@ char* errinf_to_str_servfail(struct module_qstate* qstate)
return p;
}
char* errinf_to_str_misc(struct module_qstate* qstate)
{
char buf[20480];
char* p = buf;
size_t left = sizeof(buf);
struct errinf_strlist* s;
if(!qstate->errinf)
snprintf(p, left, "misc failure");
else for(s=qstate->errinf; s; s=s->next) {
snprintf(p, left, "%s%s", (s==qstate->errinf?"":" "), s->str);
left -= strlen(p); p += strlen(p);
}
p = strdup(buf);
if(!p)
log_err("malloc failure in errinf_to_str");
return p;
}
void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr)
{
char buf[1024];

View File

@ -691,6 +691,8 @@ struct module_qstate {
struct respip_action_info* respip_action_info;
/** if the query is rpz passthru, no further rpz processing for it */
int rpz_passthru;
/* Flag tcp required. */
int tcp_required;
/** whether the reply should be dropped */
int is_drop;
@ -842,6 +844,14 @@ sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate);
*/
char* errinf_to_str_servfail(struct module_qstate* qstate);
/**
* Create error info in string. For misc failures that are not servfail.
* @param qstate: query state.
* @return string or NULL on malloc failure (already logged).
* This string is malloced and has to be freed by caller.
*/
char* errinf_to_str_misc(struct module_qstate* qstate);
/**
* Initialize the edns known options by allocating the required space.
* @param env: the module environment.

View File

@ -809,6 +809,7 @@ addr_to_nat64(const struct sockaddr_storage* addr,
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
struct sockaddr_in6 *sin6;
uint8_t *v4_byte;
int i;
/* This needs to be checked by the caller */
log_assert(addr->ss_family == AF_INET);
@ -826,7 +827,7 @@ addr_to_nat64(const struct sockaddr_storage* addr,
nat64_prefixnet = nat64_prefixnet / 8;
v4_byte = (uint8_t *)&sin->sin_addr.s_addr;
for(int i = 0; i < 4; i++) {
for(i = 0; i < 4; i++) {
if(nat64_prefixnet == 8) {
/* bits 64...71 are MBZ */
sin6->sin6_addr.s6_addr[nat64_prefixnet++] = 0;

View File

@ -124,6 +124,8 @@
/** timeout in millisec to wait for write to unblock, packets dropped after.*/
#define SEND_BLOCKED_WAIT_TIMEOUT 200
/** max number of times to wait for write to unblock, packets dropped after.*/
#define SEND_BLOCKED_MAX_RETRY 5
/** Let's make timestamping code cleaner and redefine SO_TIMESTAMP* */
#ifndef SO_TIMESTAMP
@ -410,9 +412,10 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
WSAGetLastError() == WSAENOBUFS ||
WSAGetLastError() == WSAEWOULDBLOCK) {
#endif
int retries = 0;
/* if we set the fd blocking, other threads suddenly
* have a blocking fd that they operate on */
while(sent == -1 && (
while(sent == -1 && retries < SEND_BLOCKED_MAX_RETRY && (
#ifndef USE_WINSOCK
errno == EAGAIN || errno == EINTR ||
# ifdef EWOULDBLOCK
@ -427,6 +430,13 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
#endif
)) {
#if defined(HAVE_POLL) || defined(USE_WINSOCK)
int send_nobufs = (
#ifndef USE_WINSOCK
errno == ENOBUFS
#else
WSAGetLastError() == WSAENOBUFS
#endif
);
struct pollfd p;
int pret;
memset(&p, 0, sizeof(p));
@ -465,8 +475,48 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
log_err("poll udp out failed: %s",
sock_strerror(errno));
return 0;
} else if((pret < 0 &&
#ifndef USE_WINSOCK
errno == ENOBUFS
#else
WSAGetLastError() == WSAENOBUFS
#endif
) || (send_nobufs && retries > 0)) {
/* ENOBUFS, and poll returned without
* a timeout. Or the retried send call
* returned ENOBUFS. It is good to
* wait a bit for the error to clear. */
/* The timeout is 20*(2^(retries+1)),
* it increases exponentially, starting
* at 40 msec. After 5 tries, 1240 msec
* have passed in total, when poll
* returned the error, and 1200 msec
* when send returned the errors. */
#ifndef USE_WINSOCK
pret = poll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
#else
pret = WSAPoll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
#endif
if(pret < 0 &&
#ifndef USE_WINSOCK
errno != EAGAIN && errno != EINTR &&
# ifdef EWOULDBLOCK
errno != EWOULDBLOCK &&
# endif
errno != ENOBUFS
#else
WSAGetLastError() != WSAEINPROGRESS &&
WSAGetLastError() != WSAEINTR &&
WSAGetLastError() != WSAENOBUFS &&
WSAGetLastError() != WSAEWOULDBLOCK
#endif
) {
log_err("poll udp out timer failed: %s",
sock_strerror(errno));
}
}
#endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
retries++;
if (!is_connected) {
sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
sldns_buffer_remaining(packet), 0,
@ -673,7 +723,8 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
WSAGetLastError() == WSAENOBUFS ||
WSAGetLastError() == WSAEWOULDBLOCK) {
#endif
while(sent == -1 && (
int retries = 0;
while(sent == -1 && retries < SEND_BLOCKED_MAX_RETRY && (
#ifndef USE_WINSOCK
errno == EAGAIN || errno == EINTR ||
# ifdef EWOULDBLOCK
@ -688,6 +739,13 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
#endif
)) {
#if defined(HAVE_POLL) || defined(USE_WINSOCK)
int send_nobufs = (
#ifndef USE_WINSOCK
errno == ENOBUFS
#else
WSAGetLastError() == WSAENOBUFS
#endif
);
struct pollfd p;
int pret;
memset(&p, 0, sizeof(p));
@ -726,8 +784,48 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
log_err("poll udp out failed: %s",
sock_strerror(errno));
return 0;
} else if((pret < 0 &&
#ifndef USE_WINSOCK
errno == ENOBUFS
#else
WSAGetLastError() == WSAENOBUFS
#endif
) || (send_nobufs && retries > 0)) {
/* ENOBUFS, and poll returned without
* a timeout. Or the retried send call
* returned ENOBUFS. It is good to
* wait a bit for the error to clear. */
/* The timeout is 20*(2^(retries+1)),
* it increases exponentially, starting
* at 40 msec. After 5 tries, 1240 msec
* have passed in total, when poll
* returned the error, and 1200 msec
* when send returned the errors. */
#ifndef USE_WINSOCK
pret = poll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
#else
pret = WSAPoll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
#endif
if(pret < 0 &&
#ifndef USE_WINSOCK
errno != EAGAIN && errno != EINTR &&
# ifdef EWOULDBLOCK
errno != EWOULDBLOCK &&
# endif
errno != ENOBUFS
#else
WSAGetLastError() != WSAEINPROGRESS &&
WSAGetLastError() != WSAEINTR &&
WSAGetLastError() != WSAENOBUFS &&
WSAGetLastError() != WSAEWOULDBLOCK
#endif
) {
log_err("poll udp out timer failed: %s",
sock_strerror(errno));
}
}
#endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
retries++;
sent = sendmsg(c->fd, &msg, 0);
}
}
@ -802,15 +900,18 @@ static int udp_recv_needs_log(int err)
static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
int stream) {
size_t size;
struct pp2_header *header = pp2_read_header(buf);
if(header == NULL) return 0;
struct pp2_header *header;
int err = pp2_read_header(sldns_buffer_begin(buf),
sldns_buffer_remaining(buf));
if(err) return 0;
header = (struct pp2_header*)sldns_buffer_begin(buf);
size = PP2_HEADER_SIZE + ntohs(header->len);
if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) {
/* A connection from the proxy itself.
* No need to do anything with addresses. */
goto done;
}
if(header->fam_prot == 0x00) {
if(header->fam_prot == PP2_UNSPEC_UNSPEC) {
/* Unspecified family and protocol. This could be used for
* health checks by proxies.
* No need to do anything with addresses. */
@ -818,8 +919,8 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
}
/* Read the proxied address */
switch(header->fam_prot) {
case 0x11: /* AF_INET|STREAM */
case 0x12: /* AF_INET|DGRAM */
case PP2_INET_STREAM:
case PP2_INET_DGRAM:
{
struct sockaddr_in* addr =
(struct sockaddr_in*)&rep->client_addr;
@ -830,8 +931,8 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
}
/* Ignore the destination address; it should be us. */
break;
case 0x21: /* AF_INET6|STREAM */
case 0x22: /* AF_INET6|DGRAM */
case PP2_INET6_STREAM:
case PP2_INET6_DGRAM:
{
struct sockaddr_in6* addr =
(struct sockaddr_in6*)&rep->client_addr;
@ -844,6 +945,10 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
}
/* Ignore the destination address; it should be us. */
break;
default:
log_err("proxy_protocol: unsupported family and "
"protocol 0x%x", (int)header->fam_prot);
return 0;
}
rep->is_proxied = 1;
done:
@ -858,10 +963,10 @@ done:
return 1;
}
#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
void
comm_point_udp_ancil_callback(int fd, short event, void* arg)
{
#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
struct comm_reply rep;
struct msghdr msg;
struct iovec iov[1];
@ -980,14 +1085,8 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg)
if(!rep.c || rep.c->fd == -1) /* commpoint closed */
break;
}
#else
(void)fd;
(void)event;
(void)arg;
fatal_exit("recvmsg: No support for IPV6_PKTINFO; IP_PKTINFO or IP_RECVDSTADDR. "
"Please disable interface-automatic");
#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
}
#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
void
comm_point_udp_callback(int fd, short event, void* arg)
@ -3495,19 +3594,25 @@ ssl_handle_read(struct comm_point* c)
return 0;
}
c->tcp_byte_count += r;
sldns_buffer_skip(c->buffer, r);
if(c->tcp_byte_count != current_read_size) return 1;
c->pp2_header_state = pp2_header_init;
}
}
if(c->pp2_header_state == pp2_header_init) {
header = pp2_read_header(c->buffer);
if(!header) {
int err;
err = pp2_read_header(
sldns_buffer_begin(c->buffer),
sldns_buffer_limit(c->buffer));
if(err) {
log_err("proxy_protocol: could not parse "
"PROXYv2 header");
"PROXYv2 header (%s)",
pp_lookup_error(err));
return 0;
}
header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
want_read_size = ntohs(header->len);
if(sldns_buffer_remaining(c->buffer) <
if(sldns_buffer_limit(c->buffer) <
PP2_HEADER_SIZE + want_read_size) {
log_err_addr("proxy_protocol: not enough "
"buffer size to read PROXYv2 header", "",
@ -3556,6 +3661,7 @@ ssl_handle_read(struct comm_point* c)
return 0;
}
c->tcp_byte_count += r;
sldns_buffer_skip(c->buffer, r);
if(c->tcp_byte_count != current_read_size) return 1;
c->pp2_header_state = pp2_header_done;
}
@ -3566,6 +3672,7 @@ ssl_handle_read(struct comm_point* c)
c->repinfo.remote_addrlen);
return 0;
}
sldns_buffer_flip(c->buffer);
if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
log_err_addr("proxy_protocol: could not consume "
"PROXYv2 header", "", &c->repinfo.remote_addr,
@ -3887,19 +3994,25 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
goto recv_error_initial;
}
c->tcp_byte_count += r;
sldns_buffer_skip(c->buffer, r);
if(c->tcp_byte_count != current_read_size) return 1;
c->pp2_header_state = pp2_header_init;
}
}
if(c->pp2_header_state == pp2_header_init) {
header = pp2_read_header(c->buffer);
if(!header) {
int err;
err = pp2_read_header(
sldns_buffer_begin(c->buffer),
sldns_buffer_limit(c->buffer));
if(err) {
log_err("proxy_protocol: could not parse "
"PROXYv2 header");
"PROXYv2 header (%s)",
pp_lookup_error(err));
return 0;
}
header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
want_read_size = ntohs(header->len);
if(sldns_buffer_remaining(c->buffer) <
if(sldns_buffer_limit(c->buffer) <
PP2_HEADER_SIZE + want_read_size) {
log_err_addr("proxy_protocol: not enough "
"buffer size to read PROXYv2 header", "",
@ -3926,6 +4039,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
goto recv_error;
}
c->tcp_byte_count += r;
sldns_buffer_skip(c->buffer, r);
if(c->tcp_byte_count != current_read_size) return 1;
c->pp2_header_state = pp2_header_done;
}
@ -3936,6 +4050,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
c->repinfo.remote_addrlen);
return 0;
}
sldns_buffer_flip(c->buffer);
if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
log_err_addr("proxy_protocol: could not consume "
"PROXYv2 header", "", &c->repinfo.remote_addr,
@ -5634,11 +5749,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
evbits = UB_EV_READ | UB_EV_PERSIST;
/* ub_event stuff */
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
#ifdef USE_WINSOCK
comm_point_udp_callback, c);
#else
comm_point_udp_ancil_callback, c);
#endif
if(c->ev->ev == NULL) {
log_err("could not baseset udp event");
comm_point_delete(c);
@ -5653,6 +5764,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
return c;
}
#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
struct comm_point*
comm_point_create_udp_ancil(struct comm_base *base, int fd,
sldns_buffer* buffer, int pp2_enabled,
@ -5715,6 +5827,7 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd,
c->event_added = 1;
return c;
}
#endif
struct comm_point*
comm_point_create_doq(struct comm_base *base, int fd, sldns_buffer* buffer,

View File

@ -38,102 +38,162 @@
*
* This file contains PROXY protocol functions.
*/
#include "config.h"
#include "util/log.h"
#include "util/proxy_protocol.h"
int
pp2_write_to_buf(struct sldns_buffer* buf, struct sockaddr_storage* src,
/**
* Internal struct initialized with function pointers for writing uint16 and
* uint32.
*/
struct proxy_protocol_data {
void (*write_uint16)(void* buf, uint16_t data);
void (*write_uint32)(void* buf, uint32_t data);
};
struct proxy_protocol_data pp_data;
/**
* Internal lookup table; could be further generic like sldns_lookup_table
* for all the future generic stuff.
*/
struct proxy_protocol_lookup_table {
int id;
const char *text;
};
/**
* Internal parsing error text; could be exposed with pp_lookup_error.
*/
static struct proxy_protocol_lookup_table pp_parse_errors_data[] = {
{ PP_PARSE_NOERROR, "no parse error" },
{ PP_PARSE_SIZE, "not enough space for header" },
{ PP_PARSE_WRONG_HEADERv2, "could not match PROXYv2 header" },
{ PP_PARSE_UNKNOWN_CMD, "unknown command" },
{ PP_PARSE_UNKNOWN_FAM_PROT, "unknown family and protocol" },
};
void
pp_init(void (*write_uint16)(void* buf, uint16_t data),
void (*write_uint32)(void* buf, uint32_t data)) {
pp_data.write_uint16 = write_uint16;
pp_data.write_uint32 = write_uint32;
}
const char*
pp_lookup_error(enum pp_parse_errors error) {
return pp_parse_errors_data[error].text;
}
size_t
pp2_write_to_buf(uint8_t* buf, size_t buflen,
#ifdef INET6
struct sockaddr_storage* src,
#else
struct sockaddr_in* src,
#endif
int stream)
{
int af;
size_t expected_size;
if(!src) return 0;
af = (int)((struct sockaddr_in*)src)->sin_family;
if(sldns_buffer_remaining(buf) <
PP2_HEADER_SIZE + (af==AF_INET?12:36)) {
expected_size = PP2_HEADER_SIZE + (af==AF_INET?12:36);
if(buflen < expected_size) {
return 0;
}
/* sig */
sldns_buffer_write(buf, PP2_SIG, PP2_SIG_LEN);
memcpy(buf, PP2_SIG, PP2_SIG_LEN);
buf += PP2_SIG_LEN;
/* version and command */
sldns_buffer_write_u8(buf, (PP2_VERSION << 4) | PP2_CMD_PROXY);
if(af==AF_INET) {
*buf = (PP2_VERSION << 4) | PP2_CMD_PROXY;
buf++;
switch(af) {
case AF_INET:
/* family and protocol */
sldns_buffer_write_u8(buf,
(PP2_AF_INET<<4) |
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM));
*buf = (PP2_AF_INET<<4) |
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM);
buf++;
/* length */
sldns_buffer_write_u16(buf, 12);
(*pp_data.write_uint16)(buf, 12);
buf += 2;
/* src addr */
sldns_buffer_write(buf,
memcpy(buf,
&((struct sockaddr_in*)src)->sin_addr.s_addr, 4);
buf += 4;
/* dst addr */
sldns_buffer_write_u32(buf, 0);
(*pp_data.write_uint32)(buf, 0);
buf += 4;
/* src port */
sldns_buffer_write(buf,
memcpy(buf,
&((struct sockaddr_in*)src)->sin_port, 2);
/* dst port */
sldns_buffer_write_u16(buf, 0);
} else {
/* family and protocol */
sldns_buffer_write_u8(buf,
(PP2_AF_INET6<<4) |
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM));
/* length */
sldns_buffer_write_u16(buf, 36);
/* src addr */
sldns_buffer_write(buf,
&((struct sockaddr_in6*)src)->sin6_addr, 16);
buf += 2;
/* dst addr */
sldns_buffer_set_at(buf,
sldns_buffer_position(buf), 0, 16);
sldns_buffer_skip(buf, 16);
/* src port */
sldns_buffer_write(buf,
&((struct sockaddr_in6*)src)->sin6_port, 2);
/* dst port */
sldns_buffer_write_u16(buf, 0);
(*pp_data.write_uint16)(buf, 12);
break;
#ifdef INET6
case AF_INET6:
/* family and protocol */
*buf = (PP2_AF_INET6<<4) |
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM);
buf++;
/* length */
(*pp_data.write_uint16)(buf, 36);
buf += 2;
/* src addr */
memcpy(buf,
&((struct sockaddr_in6*)src)->sin6_addr, 16);
buf += 16;
/* dst addr */
memset(buf, 0, 16);
buf += 16;
/* src port */
memcpy(buf, &((struct sockaddr_in6*)src)->sin6_port, 2);
buf += 2;
/* dst port */
(*pp_data.write_uint16)(buf, 0);
break;
#endif /* INET6 */
case AF_UNIX:
/* fallthrough */
default:
return 0;
}
return 1;
return expected_size;
}
struct pp2_header*
pp2_read_header(struct sldns_buffer* buf)
int
pp2_read_header(uint8_t* buf, size_t buflen)
{
size_t size;
struct pp2_header* header = (struct pp2_header*)sldns_buffer_begin(buf);
struct pp2_header* header = (struct pp2_header*)buf;
/* Try to fail all the unsupported cases first. */
if(sldns_buffer_remaining(buf) < PP2_HEADER_SIZE) {
log_err("proxy_protocol: not enough space for header");
return NULL;
if(buflen < PP2_HEADER_SIZE) {
return PP_PARSE_SIZE;
}
/* Check for PROXYv2 header */
if(memcmp(header, PP2_SIG, PP2_SIG_LEN) != 0 ||
((header->ver_cmd & 0xF0)>>4) != PP2_VERSION) {
log_err("proxy_protocol: could not match PROXYv2 header");
return NULL;
return PP_PARSE_WRONG_HEADERv2;
}
/* Check the length */
size = PP2_HEADER_SIZE + ntohs(header->len);
if(sldns_buffer_remaining(buf) < size) {
log_err("proxy_protocol: not enough space for header");
return NULL;
if(buflen < size) {
return PP_PARSE_SIZE;
}
/* Check for supported commands */
if((header->ver_cmd & 0xF) != PP2_CMD_LOCAL &&
(header->ver_cmd & 0xF) != PP2_CMD_PROXY) {
log_err("proxy_protocol: unsupported command");
return NULL;
return PP_PARSE_UNKNOWN_CMD;
}
/* Check for supported family and protocol */
if(header->fam_prot != 0x00 /* AF_UNSPEC|UNSPEC */ &&
header->fam_prot != 0x11 /* AF_INET|STREAM */ &&
header->fam_prot != 0x12 /* AF_INET|DGRAM */ &&
header->fam_prot != 0x21 /* AF_INET6|STREAM */ &&
header->fam_prot != 0x22 /* AF_INET6|DGRAM */) {
log_err("proxy_protocol: unsupported family and protocol");
return NULL;
if(header->fam_prot != PP2_UNSPEC_UNSPEC &&
header->fam_prot != PP2_INET_STREAM &&
header->fam_prot != PP2_INET_DGRAM &&
header->fam_prot != PP2_INET6_STREAM &&
header->fam_prot != PP2_INET6_DGRAM &&
header->fam_prot != PP2_UNIX_STREAM &&
header->fam_prot != PP2_UNIX_DGRAM) {
return PP_PARSE_UNKNOWN_FAM_PROT;
}
/* We have a correct header */
return header;
return PP_PARSE_NOERROR;
}

View File

@ -42,7 +42,7 @@
#ifndef PROXY_PROTOCOL_H
#define PROXY_PROTOCOL_H
#include "sldns/sbuffer.h"
#include "config.h"
/** PROXYv2 minimum header size */
#define PP2_HEADER_SIZE 16
@ -51,11 +51,11 @@
#define PP2_SIG "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
#define PP2_SIG_LEN 12
/** PROXYv2 version */
/** PROXYv2 version (protocol value) */
#define PP2_VERSION 0x2
/**
* PROXYv2 command.
* PROXYv2 command (protocol value).
*/
enum pp2_command {
PP2_CMD_LOCAL = 0x0,
@ -63,7 +63,7 @@ enum pp2_command {
};
/**
* PROXYv2 address family.
* PROXYv2 address family (protocol value).
*/
enum pp2_af {
PP2_AF_UNSPEC = 0x0,
@ -73,7 +73,7 @@ enum pp2_af {
};
/**
* PROXYv2 protocol.
* PROXYv2 protocol (protocol value).
*/
enum pp2_protocol {
PP2_PROT_UNSPEC = 0x0,
@ -81,6 +81,19 @@ enum pp2_protocol {
PP2_PROT_DGRAM = 0x2
};
/**
* Expected combinations of address family and protocol values used in checks.
*/
enum pp2_af_protocol_combination {
PP2_UNSPEC_UNSPEC = (PP2_AF_UNSPEC<<4)|PP2_PROT_UNSPEC,
PP2_INET_STREAM = (PP2_AF_INET<<4)|PP2_PROT_STREAM,
PP2_INET_DGRAM = (PP2_AF_INET<<4)|PP2_PROT_DGRAM,
PP2_INET6_STREAM = (PP2_AF_INET6<<4)|PP2_PROT_STREAM,
PP2_INET6_DGRAM = (PP2_AF_INET6<<4)|PP2_PROT_DGRAM,
PP2_UNIX_STREAM = (PP2_AF_UNIX<<4)|PP2_PROT_STREAM,
PP2_UNIX_DGRAM = (PP2_AF_UNIX<<4)|PP2_PROT_DGRAM
};
/**
* PROXYv2 header.
*/
@ -109,23 +122,56 @@ struct pp2_header {
} addr;
};
/**
* PROXY parse errors.
*/
enum pp_parse_errors {
PP_PARSE_NOERROR = 0,
PP_PARSE_SIZE,
PP_PARSE_WRONG_HEADERv2,
PP_PARSE_UNKNOWN_CMD,
PP_PARSE_UNKNOWN_FAM_PROT,
};
/**
* Initialize the internal proxy structure.
* @param write_uint16: pointer to a function that can write uint16.
* @param write_uint32: pointer to a function that can write uint32.
*/
void pp_init(void (*write_uint16)(void* buf, uint16_t data),
void (*write_uint32)(void* buf, uint32_t data));
/**
* Lookup the parsing error description.
* @param error: parsing error from pp2_read_header.
* @return the description.
*/
const char* pp_lookup_error(enum pp_parse_errors error);
/**
* Write a PROXYv2 header at the current position of the buffer.
* @param buf: the buffer to write to.
* @param buf: pointer to the buffer to write data to.
* @param buflen: available size on the buffer.
* @param src: the source address.
* @param stream: if the protocol is stream or datagram.
* @return 1 on success, 0 on failure.
*/
int pp2_write_to_buf(struct sldns_buffer* buf, struct sockaddr_storage* src,
size_t pp2_write_to_buf(uint8_t* buf, size_t buflen,
#ifdef INET6
struct sockaddr_storage* src,
#else
struct sockaddr_in* src,
#endif
int stream);
/**
* Read a PROXYv2 header from the current position of the buffer.
* It does initial validation and returns a pointer to the buffer position on
* success.
* @param buf: the buffer to read from.
* @return the pointer to the buffer position on success, NULL on error.
* @param buf: pointer to the buffer data to read from.
* @param buflen: available size on the buffer.
* @return parsing error, 0 on success.
*/
struct pp2_header* pp2_read_header(struct sldns_buffer* buf);
int pp2_read_header(uint8_t* buf, size_t buflen);
#endif /* PROXY_PROTOCOL_H */

View File

@ -39,6 +39,7 @@
* This file contains functions for RFC 1982 serial number arithmetic.
*/
#include "config.h"
#include "util/rfc_1982.h"
int
compare_1982(uint32_t a, uint32_t b)

View File

@ -26,6 +26,11 @@
*/
#include "config.h"
/** EDIT
* prevent warning from -Wmissing-prototypes
*/
#include "util/siphash.h"
/* default: SipHash-2-4 */
#define cROUNDS 2
#define dROUNDS 4