sync with OpenBSD -current

This commit is contained in:
purplerain 2024-06-15 04:25:27 +00:00
parent 9dfe537fef
commit b467550def
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
72 changed files with 5497 additions and 3934 deletions

View file

@ -1,4 +1,4 @@
# $OpenBSD: funcs.pl,v 1.9 2017/11/08 22:14:02 bluhm Exp $ # $OpenBSD: funcs.pl,v 1.10 2024/06/14 15:12:57 bluhm Exp $
# Copyright (c) 2010-2017 Alexander Bluhm <bluhm@openbsd.org> # Copyright (c) 2010-2017 Alexander Bluhm <bluhm@openbsd.org>
# #
@ -16,8 +16,6 @@
use strict; use strict;
use warnings; use warnings;
no warnings 'experimental::smartmatch';
use feature 'switch';
use Errno; use Errno;
use Digest::MD5; use Digest::MD5;
use IO::Socket qw(sockatmark); use IO::Socket qw(sockatmark);
@ -40,13 +38,11 @@ sub write_stream {
$ctx->add($char); $ctx->add($char);
print $char print $char
or die ref($self), " print failed: $!"; or die ref($self), " print failed: $!";
given ($char) { if ($char =~ /9/) { $char = 'A' }
when(/9/) { $char = 'A' } elsif ($char =~ /Z/) { $char = 'a' }
when(/Z/) { $char = 'a' } elsif ($char =~ /z/) { $char = "\n" }
when(/z/) { $char = "\n" } elsif ($char =~ /\n/) { print STDERR "."; $char = '0' }
when(/\n/) { print STDERR "."; $char = '0' } else { $char++ }
default { $char++ }
}
if ($self->{sleep}) { if ($self->{sleep}) {
IO::Handle::flush(\*STDOUT); IO::Handle::flush(\*STDOUT);
sleep $self->{sleep}; sleep $self->{sleep};
@ -73,28 +69,31 @@ sub write_oob {
my $char = '0'; my $char = '0';
for (my $i = 1; $i < $len; $i++) { for (my $i = 1; $i < $len; $i++) {
$msg .= $char; $msg .= $char;
given ($char) { if ($char =~ /9/) {
when(/9/) { $ctx->add("[$char]");
$ctx->add("[$char]"); defined(send(STDOUT, $msg, MSG_OOB))
defined(send(STDOUT, $msg, MSG_OOB)) or die ref($self), " send OOB failed: $!";
or die ref($self), " send OOB failed: $!"; # If tcp urgent data is sent too fast,
# If tcp urgent data is sent too fast, # it may get overwritten and lost.
# it may get overwritten and lost. sleep .1;
sleep .1; $msg = "";
$msg = ""; $char = 'A';
$char = 'A'; } elsif ($char =~ /Z/) {
} $ctx->add($char);
when(/Z/) { $ctx->add($char); $char = 'a' } $char = 'a';
when(/z/) { $ctx->add($char); $char = "\n" } } elsif ($char =~ /z/) {
when(/\n/) { $ctx->add($char);
$ctx->add($char); $char = "\n";
defined(send(STDOUT, $msg, 0)) } elsif ($char =~ /\n/) {
or die ref($self), " send failed: $!"; $ctx->add($char);
print STDERR "."; defined(send(STDOUT, $msg, 0))
$msg = ""; or die ref($self), " send failed: $!";
$char = '0'; print STDERR ".";
} $msg = "";
default { $ctx->add($char); $char++ } $char = '0';
} else {
$ctx->add($char);
$char++;
} }
} }
if ($len) { if ($len) {
@ -125,13 +124,11 @@ sub write_datagram {
for (my $i = 1; $i < $l; $i++) { for (my $i = 1; $i < $l; $i++) {
$ctx->add($char); $ctx->add($char);
$string .= $char; $string .= $char;
given ($char) { if ($char =~ /9/) { $char = 'A' }
when(/9/) { $char = 'A' } elsif ($char =~ /Z/) { $char = 'a' }
when(/Z/) { $char = 'a' } elsif ($char =~ /z/) { $char = "\n" }
when(/z/) { $char = "\n" } elsif ($char =~ /\n/) { $char = '0' }
when(/\n/) { $char = '0' } else { $char++ }
default { $char++ }
}
} }
if ($l) { if ($l) {
$ctx->add("\n"); $ctx->add("\n");
@ -311,10 +308,12 @@ sub relay_copy {
my $self = shift; my $self = shift;
my $protocol = $self->{protocol} || "tcp"; my $protocol = $self->{protocol} || "tcp";
given ($protocol) { if ($protocol =~ /tcp/) {
when (/tcp/) { relay_copy_stream($self, @_) } relay_copy_stream($self, @_);
when (/udp/) { relay_copy_datagram($self, @_) } } elsif ($protocol =~ /udp/) {
default { die ref($self), " unknown protocol name: $protocol" } relay_copy_datagram($self, @_);
} else {
die ref($self), " unknown protocol name: $protocol";
} }
} }
@ -437,10 +436,12 @@ sub relay_splice {
my $self = shift; my $self = shift;
my $protocol = $self->{protocol} || "tcp"; my $protocol = $self->{protocol} || "tcp";
given ($protocol) { if ($protocol =~ /tcp/) {
when (/tcp/) { relay_splice_stream($self, @_) } relay_splice_stream($self, @_);
when (/udp/) { relay_splice_datagram($self, @_) } } elsif ($protocol =~ /udp/) {
default { die ref($self), " unknown protocol name: $protocol" } relay_splice_datagram($self, @_);
} else {
die ref($self), " unknown protocol name: $protocol";
} }
} }
@ -448,10 +449,12 @@ sub relay {
my $self = shift; my $self = shift;
my $forward = $self->{forward}; my $forward = $self->{forward};
given ($forward) { if ($forward =~ /copy/) {
when (/copy/) { relay_copy($self, @_) } relay_copy($self, @_);
when (/splice/) { relay_splice($self, @_) } } elsif ($forward =~ /splice/) {
default { die ref($self), " unknown forward name: $forward" } relay_splice($self, @_);
} else {
die ref($self), " unknown forward name: $forward";
} }
my $soerror; my $soerror;

View file

@ -1,4 +1,4 @@
# $OpenBSD: Makefile,v 1.134 2024/06/06 19:49:25 djm Exp $ # $OpenBSD: Makefile,v 1.135 2024/06/14 04:43:11 djm Exp $
OPENSSL?= yes OPENSSL?= yes
@ -103,7 +103,8 @@ LTESTS= connect \
match-subsystem \ match-subsystem \
agent-pkcs11-restrict \ agent-pkcs11-restrict \
agent-pkcs11-cert \ agent-pkcs11-cert \
penalty penalty \
penalty-expire
INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
INTEROP_TESTS+= dropbear-ciphers dropbear-kex INTEROP_TESTS+= dropbear-ciphers dropbear-kex

View file

@ -0,0 +1,34 @@
# $OpenBSD
# Placed in the Public Domain.
tid="penalties"
grep -vi PerSourcePenalties $OBJ/sshd_config > $OBJ/sshd_config.bak
cp $OBJ/authorized_keys_${USER} $OBJ/authorized_keys_${USER}.bak
conf() {
test -z "$PIDFILE" || stop_sshd
(cat $OBJ/sshd_config.bak ;
echo "PerSourcePenalties $@") > $OBJ/sshd_config
cp $OBJ/authorized_keys_${USER}.bak $OBJ/authorized_keys_${USER}
start_sshd
}
conf "noauth:10s authfail:10s max:20s min:1s"
verbose "test connect"
${SSH} -F $OBJ/ssh_config somehost true || fatal "basic connect failed"
verbose "penalty expiry"
# Incur a penalty
cat /dev/null > $OBJ/authorized_keys_${USER}
${SSH} -F $OBJ/ssh_config somehost true && fatal "authfail connect succeeded"
# Check denied
cp $OBJ/authorized_keys_${USER}.bak $OBJ/authorized_keys_${USER}
${SSH} -F $OBJ/ssh_config somehost true && fatal "authfail not rejected"
# Let it expire and try again.
sleep 11
${SSH} -F $OBJ/ssh_config somehost true || fail "authfail not expired"

View file

@ -14,7 +14,7 @@ conf() {
start_sshd start_sshd
} }
conf "noauth:10s authfail:6s grace-exceeded:10s min:8s max:20s" conf "authfail:30s min:50s max:200s"
verbose "test connect" verbose "test connect"
${SSH} -F $OBJ/ssh_config somehost true || fatal "basic connect failed" ${SSH} -F $OBJ/ssh_config somehost true || fatal "basic connect failed"
@ -36,13 +36,10 @@ cp $OBJ/authorized_keys_${USER}.bak $OBJ/authorized_keys_${USER}
# These should be refused by the active penalty # These should be refused by the active penalty
${SSH} -F $OBJ/ssh_config somehost true && fail "authfail not rejected" ${SSH} -F $OBJ/ssh_config somehost true && fail "authfail not rejected"
sleep 5
${SSH} -F $OBJ/ssh_config somehost true && fail "repeat authfail not rejected" ${SSH} -F $OBJ/ssh_config somehost true && fail "repeat authfail not rejected"
# Penalty should have expired, this should succeed. conf "noauth:100s"
sleep 8 ${SSH} -F $OBJ/ssh_config somehost true || fatal "basic connect failed"
${SSH} -F $OBJ/ssh_config somehost true || fail "authfail not expired"
verbose "penalty for no authentication" verbose "penalty for no authentication"
${SSHKEYSCAN} -t ssh-ed25519 -p $PORT 127.0.0.1 >/dev/null || fatal "keyscan failed" ${SSHKEYSCAN} -t ssh-ed25519 -p $PORT 127.0.0.1 >/dev/null || fatal "keyscan failed"

View file

@ -1,4 +1,4 @@
# $OpenBSD: funcs.pl,v 1.9 2021/12/22 15:54:01 bluhm Exp $ # $OpenBSD: funcs.pl,v 1.10 2024/06/14 15:12:57 bluhm Exp $
# Copyright (c) 2010-2021 Alexander Bluhm <bluhm@openbsd.org> # Copyright (c) 2010-2021 Alexander Bluhm <bluhm@openbsd.org>
# #
@ -16,10 +16,9 @@
use strict; use strict;
use warnings; use warnings;
no warnings 'experimental::smartmatch';
use feature 'switch';
use Errno; use Errno;
use Digest::MD5; use Digest::MD5;
use POSIX;
use Socket; use Socket;
use Socket6; use Socket6;
use IO::Socket; use IO::Socket;
@ -63,13 +62,11 @@ sub write_char {
$ctx->add($char); $ctx->add($char);
print $char print $char
or die ref($self), " print failed: $!"; or die ref($self), " print failed: $!";
given ($char) { if ($char =~ /9/) { $char = 'A' }
when(/9/) { $char = 'A' } elsif ($char =~ /Z/) { $char = 'a' }
when(/Z/) { $char = 'a' } elsif ($char =~ /z/) { $char = "\n" }
when(/z/) { $char = "\n" } elsif ($char =~ /\n/) { print STDERR "."; $char = '0' }
when(/\n/) { print STDERR "."; $char = '0' } else { $char++ }
default { $char++ }
}
if ($self->{sleep}) { if ($self->{sleep}) {
IO::Handle::flush(\*STDOUT); IO::Handle::flush(\*STDOUT);
sleep $self->{sleep}; sleep $self->{sleep};
@ -313,7 +310,6 @@ sub read_multipart {
print STDERR "LEN: ", $len, "\n"; print STDERR "LEN: ", $len, "\n";
print STDERR "MD5: ", $ctx->hexdigest, "\n"; print STDERR "MD5: ", $ctx->hexdigest, "\n";
} }
sub errignore { sub errignore {

View file

@ -1,4 +1,4 @@
# $OpenBSD: funcs.pl,v 1.25 2021/12/22 11:50:28 bluhm Exp $ # $OpenBSD: funcs.pl,v 1.26 2024/06/14 15:12:57 bluhm Exp $
# Copyright (c) 2010-2021 Alexander Bluhm <bluhm@openbsd.org> # Copyright (c) 2010-2021 Alexander Bluhm <bluhm@openbsd.org>
# #
@ -16,8 +16,6 @@
use strict; use strict;
use warnings; use warnings;
no warnings 'experimental::smartmatch';
use feature 'switch';
use Errno; use Errno;
use Digest::MD5; use Digest::MD5;
use Socket; use Socket;
@ -125,13 +123,11 @@ sub write_char {
$ctx->add($char); $ctx->add($char);
print $char print $char
or die ref($self), " print failed: $!"; or die ref($self), " print failed: $!";
given ($char) { if ($char =~ /9/) { $char = 'A' }
when(/9/) { $char = 'A' } elsif ($char =~ /Z/) { $char = 'a' }
when(/Z/) { $char = 'a' } elsif ($char =~ /z/) { $char = "\n" }
when(/z/) { $char = "\n" } elsif ($char =~ /\n/) { print STDERR "."; $char = '0' }
when(/\n/) { print STDERR "."; $char = '0' } else { $char++ }
default { $char++ }
}
if ($self->{sleep}) { if ($self->{sleep}) {
IO::Handle::flush(\*STDOUT); IO::Handle::flush(\*STDOUT);
sleep $self->{sleep}; sleep $self->{sleep};
@ -521,6 +517,15 @@ sub check_logs {
and die "relayd lost child"; and die "relayd lost child";
} }
sub array_eq {
my ($a, $b) = @_;
return if @$a != @$b;
for (my $i = 0; $i < @$a; $i++) {
return if $$a[$i] ne $$b[$i];
}
return 1;
}
sub check_len { sub check_len {
my ($c, $r, $s, %args) = @_; my ($c, $r, $s, %args) = @_;
@ -531,7 +536,7 @@ sub check_len {
unless $args{client}{nocheck}; unless $args{client}{nocheck};
@slen = $s->loggrep(qr/^LEN: /) or die "no server len" @slen = $s->loggrep(qr/^LEN: /) or die "no server len"
unless $args{server}{nocheck}; unless $args{server}{nocheck};
!@clen || !@slen || @clen ~~ @slen !@clen || !@slen || array_eq \@clen, \@slen
or die "client: @clen", "server: @slen", "len mismatch"; or die "client: @clen", "server: @slen", "len mismatch";
!defined($args{len}) || !$clen[0] || $clen[0] eq "LEN: $args{len}\n" !defined($args{len}) || !$clen[0] || $clen[0] eq "LEN: $args{len}\n"
or die "client: $clen[0]", "len $args{len} expected"; or die "client: $clen[0]", "len $args{len} expected";

View file

@ -1,4 +1,4 @@
# $OpenBSD: funcs.pl,v 1.40 2022/03/25 14:15:10 bluhm Exp $ # $OpenBSD: funcs.pl,v 1.41 2024/06/14 15:12:57 bluhm Exp $
# Copyright (c) 2010-2021 Alexander Bluhm <bluhm@openbsd.org> # Copyright (c) 2010-2021 Alexander Bluhm <bluhm@openbsd.org>
# #
@ -16,8 +16,6 @@
use strict; use strict;
use warnings; use warnings;
no warnings 'experimental::smartmatch';
use feature 'switch';
use Errno; use Errno;
use List::Util qw(first); use List::Util qw(first);
use Socket; use Socket;
@ -152,12 +150,10 @@ sub generate_chars {
my $char = '0'; my $char = '0';
for (my $i = 0; $i < $len; $i++) { for (my $i = 0; $i < $len; $i++) {
$msg .= $char; $msg .= $char;
given ($char) { if ($char =~ /9/) { $char = 'A' }
when(/9/) { $char = 'A' } elsif ($char =~ /Z/) { $char = 'a' }
when(/Z/) { $char = 'a' } elsif ($char =~ /z/) { $char = '0' }
when(/z/) { $char = '0' } else { $char++ }
default { $char++ }
}
} }
return $msg; return $msg;
} }

View file

@ -380,8 +380,8 @@
/* Define to 1 if you have the `memmove' function. */ /* Define to 1 if you have the `memmove' function. */
#define HAVE_MEMMOVE 1 #define HAVE_MEMMOVE 1
/* Define to 1 if you have the <memory.h> header file. */ /* Define to 1 if you have the <minix/config.h> header file. */
#define HAVE_MEMORY_H 1 /* #undef HAVE_MINIX_CONFIG_H */
/* Define to 1 if you have the <netdb.h> header file. */ /* Define to 1 if you have the <netdb.h> header file. */
#define HAVE_NETDB_H 1 #define HAVE_NETDB_H 1
@ -588,6 +588,9 @@
/* Define to 1 if you have the <stdint.h> header file. */ /* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1 #define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */ /* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1 #define HAVE_STDLIB_H 1
@ -690,6 +693,9 @@
/* Define to 1 if you have the <vfork.h> header file. */ /* Define to 1 if you have the <vfork.h> header file. */
/* #undef HAVE_VFORK_H */ /* #undef HAVE_VFORK_H */
/* Define to 1 if you have the <wchar.h> header file. */
#define HAVE_WCHAR_H 1
/* Define to 1 if you have the <windows.h> header file. */ /* Define to 1 if you have the <windows.h> header file. */
/* #undef HAVE_WINDOWS_H */ /* #undef HAVE_WINDOWS_H */
@ -773,7 +779,7 @@
#define PACKAGE_NAME "unbound" #define PACKAGE_NAME "unbound"
/* Define to the full name and version of this package. */ /* Define to the full name and version of this package. */
#define PACKAGE_STRING "unbound 1.19.3" #define PACKAGE_STRING "unbound 1.20.0"
/* Define to the one symbol short name of this package. */ /* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "unbound" #define PACKAGE_TARNAME "unbound"
@ -782,7 +788,7 @@
#define PACKAGE_URL "" #define PACKAGE_URL ""
/* Define to the version of this package. */ /* Define to the version of this package. */
#define PACKAGE_VERSION "1.19.3" #define PACKAGE_VERSION "1.20.0"
/* default pidfile location */ /* default pidfile location */
#define PIDFILE "" #define PIDFILE ""
@ -805,7 +811,7 @@
#define ROOT_CERT_FILE "/var/unbound/etc/icannbundle.pem" #define ROOT_CERT_FILE "/var/unbound/etc/icannbundle.pem"
/* version number for resource files */ /* version number for resource files */
#define RSRC_PACKAGE_VERSION 1,19,3,0 #define RSRC_PACKAGE_VERSION 1,20,0,0
/* Directory to chdir to */ /* Directory to chdir to */
#define RUN_DIR "/var/unbound/etc" #define RUN_DIR "/var/unbound/etc"
@ -831,7 +837,9 @@
/* Define to 1 if libsodium supports sodium_set_misuse_handler */ /* Define to 1 if libsodium supports sodium_set_misuse_handler */
/* #undef SODIUM_MISUSE_HANDLER */ /* #undef SODIUM_MISUSE_HANDLER */
/* Define to 1 if you have the ANSI C header files. */ /* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#define STDC_HEADERS 1 #define STDC_HEADERS 1
/* use default strptime. */ /* use default strptime. */
@ -927,21 +935,87 @@
#ifndef _ALL_SOURCE #ifndef _ALL_SOURCE
# define _ALL_SOURCE 1 # define _ALL_SOURCE 1
#endif #endif
/* Enable general extensions on macOS. */
#ifndef _DARWIN_C_SOURCE
# define _DARWIN_C_SOURCE 1
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
/* Enable GNU extensions on systems that have them. */ /* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
# define _GNU_SOURCE 1 # define _GNU_SOURCE 1
#endif #endif
/* Enable threading extensions on Solaris. */ /* Enable X/Open compliant socket functions that do not require linking
with -lxnet on HP-UX 11.11. */
#ifndef _HPUX_ALT_XOPEN_SOCKET_API
# define _HPUX_ALT_XOPEN_SOCKET_API 1
#endif
/* Identify the host operating system as Minix.
This macro does not affect the system headers' behavior.
A future release of Autoconf may stop defining this macro. */
#ifndef _MINIX
/* # undef _MINIX */
#endif
/* Enable general extensions on NetBSD.
Enable NetBSD compatibility extensions on Minix. */
#ifndef _NETBSD_SOURCE
# define _NETBSD_SOURCE 1
#endif
/* Enable OpenBSD compatibility extensions on NetBSD.
Oddly enough, this does nothing on OpenBSD. */
#ifndef _OPENBSD_SOURCE
# define _OPENBSD_SOURCE 1
#endif
/* Define to 1 if needed for POSIX-compatible behavior. */
#ifndef _POSIX_SOURCE
/* # undef _POSIX_SOURCE */
#endif
/* Define to 2 if needed for POSIX-compatible behavior. */
#ifndef _POSIX_1_SOURCE
/* # undef _POSIX_1_SOURCE */
#endif
/* Enable POSIX-compatible threading on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS #ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1 # define _POSIX_PTHREAD_SEMANTICS 1
#endif #endif
/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
# define __STDC_WANT_IEC_60559_BFP_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
# define __STDC_WANT_IEC_60559_DFP_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
#endif
/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
#ifndef __STDC_WANT_LIB_EXT2__
# define __STDC_WANT_LIB_EXT2__ 1
#endif
/* Enable extensions specified by ISO/IEC 24747:2009. */
#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
# define __STDC_WANT_MATH_SPEC_FUNCS__ 1
#endif
/* Enable extensions on HP NonStop. */ /* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE #ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1 # define _TANDEM_SOURCE 1
#endif #endif
/* Enable general extensions on Solaris. */ /* Enable X/Open extensions. Define to 500 only if necessary
#ifndef __EXTENSIONS__ to make mbstate_t available. */
# define __EXTENSIONS__ 1 #ifndef _XOPEN_SOURCE
/* # undef _XOPEN_SOURCE */
#endif #endif
@ -967,11 +1041,6 @@
`char[]'. */ `char[]'. */
#define YYTEXT_POINTER 1 #define YYTEXT_POINTER 1
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */ /* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */ /* #undef _FILE_OFFSET_BITS */
@ -981,18 +1050,8 @@
/* Define for large files, on AIX-style hosts. */ /* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */ /* #undef _LARGE_FILES */
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Enable for compile on Minix */ /* Enable for compile on Minix */
/* #undef _NETBSD_SOURCE */ #define _NETBSD_SOURCE 1
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
/* defined to use gcc ansi snprintf and sscanf that understands %lld when /* defined to use gcc ansi snprintf and sscanf that understands %lld when
compiled for windows. */ compiled for windows. */
@ -1034,7 +1093,7 @@
/* Define to `long int' if <sys/types.h> does not define. */ /* Define to `long int' if <sys/types.h> does not define. */
/* #undef off_t */ /* #undef off_t */
/* Define to `int' if <sys/types.h> does not define. */ /* Define as a signed integer type capable of holding a process identifier. */
/* #undef pid_t */ /* #undef pid_t */
/* Define to 'int' if not defined */ /* Define to 'int' if not defined */

View file

@ -71,6 +71,7 @@ forwards_create(void)
sizeof(struct iter_forwards)); sizeof(struct iter_forwards));
if(!fwd) if(!fwd)
return NULL; return NULL;
lock_rw_init(&fwd->lock);
return fwd; return fwd;
} }
@ -100,6 +101,7 @@ forwards_delete(struct iter_forwards* fwd)
{ {
if(!fwd) if(!fwd)
return; return;
lock_rw_destroy(&fwd->lock);
fwd_del_tree(fwd); fwd_del_tree(fwd);
free(fwd); free(fwd);
} }
@ -332,45 +334,64 @@ make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg)
int int
forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg) forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg)
{ {
if(fwd->tree) {
lock_unprotect(&fwd->lock, fwd->tree);
}
fwd_del_tree(fwd); fwd_del_tree(fwd);
fwd->tree = rbtree_create(fwd_cmp); fwd->tree = rbtree_create(fwd_cmp);
if(!fwd->tree) if(!fwd->tree)
return 0; return 0;
lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree));
lock_rw_wrlock(&fwd->lock);
/* read forward zones */ /* read forward zones */
if(!read_forwards(fwd, cfg)) if(!read_forwards(fwd, cfg)) {
lock_rw_unlock(&fwd->lock);
return 0; return 0;
if(!make_stub_holes(fwd, cfg)) }
if(!make_stub_holes(fwd, cfg)) {
lock_rw_unlock(&fwd->lock);
return 0; return 0;
}
fwd_init_parents(fwd); fwd_init_parents(fwd);
lock_rw_unlock(&fwd->lock);
return 1; return 1;
} }
struct delegpt* struct delegpt*
forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass) forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass,
int nolock)
{ {
rbnode_type* res = NULL; struct iter_forward_zone* res;
struct iter_forward_zone key; struct iter_forward_zone key;
int has_dp;
key.node.key = &key; key.node.key = &key;
key.dclass = qclass; key.dclass = qclass;
key.name = qname; key.name = qname;
key.namelabs = dname_count_size_labels(qname, &key.namelen); key.namelabs = dname_count_size_labels(qname, &key.namelen);
res = rbtree_search(fwd->tree, &key); /* lock_() calls are macros that could be nothing, surround in {} */
if(res) return ((struct iter_forward_zone*)res)->dp; if(!nolock) { lock_rw_rdlock(&fwd->lock); }
return NULL; res = (struct iter_forward_zone*)rbtree_search(fwd->tree, &key);
has_dp = res && res->dp;
if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); }
return has_dp?res->dp:NULL;
} }
struct delegpt* struct delegpt*
forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass) forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass,
int nolock)
{ {
/* lookup the forward zone in the tree */ /* lookup the forward zone in the tree */
rbnode_type* res = NULL; rbnode_type* res = NULL;
struct iter_forward_zone *result; struct iter_forward_zone *result;
struct iter_forward_zone key; struct iter_forward_zone key;
int has_dp;
key.node.key = &key; key.node.key = &key;
key.dclass = qclass; key.dclass = qclass;
key.name = qname; key.name = qname;
key.namelabs = dname_count_size_labels(qname, &key.namelen); key.namelabs = dname_count_size_labels(qname, &key.namelen);
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_rdlock(&fwd->lock); }
if(rbtree_find_less_equal(fwd->tree, &key, &res)) { if(rbtree_find_less_equal(fwd->tree, &key, &res)) {
/* exact */ /* exact */
result = (struct iter_forward_zone*)res; result = (struct iter_forward_zone*)res;
@ -378,8 +399,10 @@ forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
/* smaller element (or no element) */ /* smaller element (or no element) */
int m; int m;
result = (struct iter_forward_zone*)res; result = (struct iter_forward_zone*)res;
if(!result || result->dclass != qclass) if(!result || result->dclass != qclass) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return NULL; return NULL;
}
/* count number of labels matched */ /* count number of labels matched */
(void)dname_lab_cmp(result->name, result->namelabs, key.name, (void)dname_lab_cmp(result->name, result->namelabs, key.name,
key.namelabs, &m); key.namelabs, &m);
@ -389,20 +412,22 @@ forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
result = result->parent; result = result->parent;
} }
} }
if(result) has_dp = result && result->dp;
return result->dp; if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); }
return NULL; return has_dp?result->dp:NULL;
} }
struct delegpt* struct delegpt*
forwards_lookup_root(struct iter_forwards* fwd, uint16_t qclass) forwards_lookup_root(struct iter_forwards* fwd, uint16_t qclass, int nolock)
{ {
uint8_t root = 0; uint8_t root = 0;
return forwards_lookup(fwd, &root, qclass); return forwards_lookup(fwd, &root, qclass, nolock);
} }
int /* Finds next root item in forwards lookup tree.
forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass) * Caller needs to handle locking of the forwards structure. */
static int
next_root_locked(struct iter_forwards* fwd, uint16_t* dclass)
{ {
struct iter_forward_zone key; struct iter_forward_zone key;
rbnode_type* n; rbnode_type* n;
@ -419,7 +444,7 @@ forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass)
} }
/* root not first item? search for higher items */ /* root not first item? search for higher items */
*dclass = p->dclass + 1; *dclass = p->dclass + 1;
return forwards_next_root(fwd, dclass); return next_root_locked(fwd, dclass);
} }
/* find class n in tree, we may get a direct hit, or if we don't /* find class n in tree, we may get a direct hit, or if we don't
* this is the last item of the previous class so rbtree_next() takes * this is the last item of the previous class so rbtree_next() takes
@ -447,10 +472,21 @@ forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass)
} }
/* not a root node, return next higher item */ /* not a root node, return next higher item */
*dclass = p->dclass+1; *dclass = p->dclass+1;
return forwards_next_root(fwd, dclass); return next_root_locked(fwd, dclass);
} }
} }
int
forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass, int nolock)
{
int ret;
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_rdlock(&fwd->lock); }
ret = next_root_locked(fwd, dclass);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return ret;
}
size_t size_t
forwards_get_mem(struct iter_forwards* fwd) forwards_get_mem(struct iter_forwards* fwd)
{ {
@ -458,10 +494,12 @@ forwards_get_mem(struct iter_forwards* fwd)
size_t s; size_t s;
if(!fwd) if(!fwd)
return 0; return 0;
lock_rw_rdlock(&fwd->lock);
s = sizeof(*fwd) + sizeof(*fwd->tree); s = sizeof(*fwd) + sizeof(*fwd->tree);
RBTREE_FOR(p, struct iter_forward_zone*, fwd->tree) { RBTREE_FOR(p, struct iter_forward_zone*, fwd->tree) {
s += sizeof(*p) + p->namelen + delegpt_get_mem(p->dp); s += sizeof(*p) + p->namelen + delegpt_get_mem(p->dp);
} }
lock_rw_unlock(&fwd->lock);
return s; return s;
} }
@ -477,49 +515,78 @@ fwd_zone_find(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
} }
int int
forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp) forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp,
int nolock)
{ {
struct iter_forward_zone *z; struct iter_forward_zone *z;
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
if((z=fwd_zone_find(fwd, c, dp->name)) != NULL) { if((z=fwd_zone_find(fwd, c, dp->name)) != NULL) {
(void)rbtree_delete(fwd->tree, &z->node); (void)rbtree_delete(fwd->tree, &z->node);
fwd_zone_free(z); fwd_zone_free(z);
} }
if(!forwards_insert(fwd, c, dp)) if(!forwards_insert(fwd, c, dp)) {
return 0; if(!nolock) { lock_rw_unlock(&fwd->lock); }
fwd_init_parents(fwd);
return 1;
}
void
forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
{
struct iter_forward_zone *z;
if(!(z=fwd_zone_find(fwd, c, nm)))
return; /* nothing to do */
(void)rbtree_delete(fwd->tree, &z->node);
fwd_zone_free(z);
fwd_init_parents(fwd);
}
int
forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
{
if(!fwd_add_stub_hole(fwd, c, nm)) {
return 0; return 0;
} }
fwd_init_parents(fwd); fwd_init_parents(fwd);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return 1; return 1;
} }
void void
forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm) forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
int nolock)
{ {
struct iter_forward_zone *z; struct iter_forward_zone *z;
if(!(z=fwd_zone_find(fwd, c, nm))) /* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
if(!(z=fwd_zone_find(fwd, c, nm))) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return; /* nothing to do */ return; /* nothing to do */
if(z->dp != NULL) }
return; /* not a stub hole */
(void)rbtree_delete(fwd->tree, &z->node); (void)rbtree_delete(fwd->tree, &z->node);
fwd_zone_free(z); fwd_zone_free(z);
fwd_init_parents(fwd); fwd_init_parents(fwd);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
}
int
forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
int nolock)
{
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
if(fwd_zone_find(fwd, c, nm) != NULL) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return 1; /* already a stub zone there */
}
if(!fwd_add_stub_hole(fwd, c, nm)) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return 0;
}
fwd_init_parents(fwd);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return 1;
}
void
forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
uint8_t* nm, int nolock)
{
struct iter_forward_zone *z;
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
if(!(z=fwd_zone_find(fwd, c, nm))) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return; /* nothing to do */
}
if(z->dp != NULL) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return; /* not a stub hole */
}
(void)rbtree_delete(fwd->tree, &z->node);
fwd_zone_free(z);
fwd_init_parents(fwd);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
} }

View file

@ -43,6 +43,7 @@
#ifndef ITERATOR_ITER_FWD_H #ifndef ITERATOR_ITER_FWD_H
#define ITERATOR_ITER_FWD_H #define ITERATOR_ITER_FWD_H
#include "util/rbtree.h" #include "util/rbtree.h"
#include "util/locks.h"
struct config_file; struct config_file;
struct delegpt; struct delegpt;
@ -50,6 +51,11 @@ struct delegpt;
* Iterator forward zones structure * Iterator forward zones structure
*/ */
struct iter_forwards { struct iter_forwards {
/** lock on the forwards tree.
* When grabbing both this lock and the anchors.lock, this lock
* is grabbed first. When grabbing both this lock and the hints.lock
* this lock is grabbed first. */
lock_rw_type lock;
/** /**
* Zones are stored in this tree. Sort order is specially chosen. * Zones are stored in this tree. Sort order is specially chosen.
* first sorted on qclass. Then on dname in nsec-like order, so that * first sorted on qclass. Then on dname in nsec-like order, so that
@ -106,47 +112,65 @@ int forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg);
/** /**
* Find forward zone exactly by name * Find forward zone exactly by name
* The return value is contents of the forwards structure.
* Caller should lock and unlock a readlock on the forwards structure if nolock
* is set.
* Otherwise caller should unlock the readlock on the forwards structure if a
* value was returned.
* @param fwd: forward storage. * @param fwd: forward storage.
* @param qname: The qname of the query. * @param qname: The qname of the query.
* @param qclass: The qclass of the query. * @param qclass: The qclass of the query.
* @param nolock: Skip locking, locking is handled by the caller.
* @return: A delegation point or null. * @return: A delegation point or null.
*/ */
struct delegpt* forwards_find(struct iter_forwards* fwd, uint8_t* qname, struct delegpt* forwards_find(struct iter_forwards* fwd, uint8_t* qname,
uint16_t qclass); uint16_t qclass, int nolock);
/** /**
* Find forward zone information * Find forward zone information
* For this qname/qclass find forward zone information, returns delegation * For this qname/qclass find forward zone information, returns delegation
* point with server names and addresses, or NULL if no forwarding is needed. * point with server names and addresses, or NULL if no forwarding is needed.
* The return value is contents of the forwards structure.
* Caller should lock and unlock a readlock on the forwards structure if nolock
* is set.
* Otherwise caller should unlock the readlock on the forwards structure if a
* value was returned.
* *
* @param fwd: forward storage. * @param fwd: forward storage.
* @param qname: The qname of the query. * @param qname: The qname of the query.
* @param qclass: The qclass of the query. * @param qclass: The qclass of the query.
* @param nolock: Skip locking, locking is handled by the caller.
* @return: A delegation point if the query has to be forwarded to that list, * @return: A delegation point if the query has to be forwarded to that list,
* otherwise null. * otherwise null.
*/ */
struct delegpt* forwards_lookup(struct iter_forwards* fwd, struct delegpt* forwards_lookup(struct iter_forwards* fwd,
uint8_t* qname, uint16_t qclass); uint8_t* qname, uint16_t qclass, int nolock);
/** /**
* Same as forwards_lookup, but for the root only * Same as forwards_lookup, but for the root only
* @param fwd: forward storage. * @param fwd: forward storage.
* @param qclass: The qclass of the query. * @param qclass: The qclass of the query.
* @param nolock: Skip locking, locking is handled by the caller.
* @return: A delegation point if root forward exists, otherwise null. * @return: A delegation point if root forward exists, otherwise null.
*/ */
struct delegpt* forwards_lookup_root(struct iter_forwards* fwd, struct delegpt* forwards_lookup_root(struct iter_forwards* fwd,
uint16_t qclass); uint16_t qclass, int nolock);
/** /**
* Find next root item in forwards lookup tree. * Find next root item in forwards lookup tree.
* Handles its own locking unless nolock is set. In that case the caller
* should lock and unlock a readlock on the forwards structure.
* @param fwd: the forward storage * @param fwd: the forward storage
* @param qclass: class to look at next, or higher. * @param qclass: class to look at next, or higher.
* @param nolock: Skip locking, locking is handled by the caller.
* @return false if none found, or if true stored in qclass. * @return false if none found, or if true stored in qclass.
*/ */
int forwards_next_root(struct iter_forwards* fwd, uint16_t* qclass); int forwards_next_root(struct iter_forwards* fwd, uint16_t* qclass,
int nolock);
/** /**
* Get memory in use by forward storage * Get memory in use by forward storage
* Locks and unlocks the structure.
* @param fwd: forward storage. * @param fwd: forward storage.
* @return bytes in use * @return bytes in use
*/ */
@ -158,42 +182,56 @@ int fwd_cmp(const void* k1, const void* k2);
/** /**
* Add zone to forward structure. For external use since it recalcs * Add zone to forward structure. For external use since it recalcs
* the tree parents. * the tree parents.
* Handles its own locking unless nolock is set. In that case the caller
* should lock and unlock a writelock on the forwards structure.
* @param fwd: the forward data structure * @param fwd: the forward data structure
* @param c: class of zone * @param c: class of zone
* @param dp: delegation point with name and target nameservers for new * @param dp: delegation point with name and target nameservers for new
* forward zone. malloced. * forward zone. malloced.
* @param nolock: Skip locking, locking is handled by the caller.
* @return false on failure (out of memory); * @return false on failure (out of memory);
*/ */
int forwards_add_zone(struct iter_forwards* fwd, uint16_t c, int forwards_add_zone(struct iter_forwards* fwd, uint16_t c,
struct delegpt* dp); struct delegpt* dp, int nolock);
/** /**
* Remove zone from forward structure. For external use since it * Remove zone from forward structure. For external use since it
* recalcs the tree parents. * recalcs the tree parents.
* Handles its own locking unless nolock is set. In that case the caller
* should lock and unlock a writelock on the forwards structure.
* @param fwd: the forward data structure * @param fwd: the forward data structure
* @param c: class of zone * @param c: class of zone
* @param nm: name of zone (in uncompressed wireformat). * @param nm: name of zone (in uncompressed wireformat).
* @param nolock: Skip locking, locking is handled by the caller.
*/ */
void forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm); void forwards_delete_zone(struct iter_forwards* fwd, uint16_t c,
uint8_t* nm, int nolock);
/** /**
* Add stub hole (empty entry in forward table, that makes resolution skip * Add stub hole (empty entry in forward table, that makes resolution skip
* a forward-zone because the stub zone should override the forward zone). * a forward-zone because the stub zone should override the forward zone).
* Does not add one if not necessary. * Does not add one if not necessary.
* Handles its own locking unless nolock is set. In that case the caller
* should lock and unlock a writelock on the forwards structure.
* @param fwd: the forward data structure * @param fwd: the forward data structure
* @param c: class of zone * @param c: class of zone
* @param nm: name of zone (in uncompressed wireformat). * @param nm: name of zone (in uncompressed wireformat).
* @param nolock: Skip locking, locking is handled by the caller.
* @return false on failure (out of memory); * @return false on failure (out of memory);
*/ */
int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm); int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c,
uint8_t* nm, int nolock);
/** /**
* Remove stub hole, if one exists. * Remove stub hole, if one exists.
* Handles its own locking unless nolock is set. In that case the caller
* should lock and unlock a writelock on the forwards structure.
* @param fwd: the forward data structure * @param fwd: the forward data structure
* @param c: class of zone * @param c: class of zone
* @param nm: name of zone (in uncompressed wireformat). * @param nm: name of zone (in uncompressed wireformat).
* @param nolock: Skip locking, locking is handled by the caller.
*/ */
void forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, void forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
uint8_t* nm); uint8_t* nm, int nolock);
#endif /* ITERATOR_ITER_FWD_H */ #endif /* ITERATOR_ITER_FWD_H */

View file

@ -57,6 +57,8 @@ hints_create(void)
sizeof(struct iter_hints)); sizeof(struct iter_hints));
if(!hints) if(!hints)
return NULL; return NULL;
lock_rw_init(&hints->lock);
lock_protect(&hints->lock, &hints->tree, sizeof(hints->tree));
return hints; return hints;
} }
@ -83,6 +85,7 @@ hints_delete(struct iter_hints* hints)
{ {
if(!hints) if(!hints)
return; return;
lock_rw_destroy(&hints->lock);
hints_del_tree(hints); hints_del_tree(hints);
free(hints); free(hints);
} }
@ -438,47 +441,70 @@ read_root_hints_list(struct iter_hints* hints, struct config_file* cfg)
int int
hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg) hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
{ {
int nolock = 1;
lock_rw_wrlock(&hints->lock);
hints_del_tree(hints); hints_del_tree(hints);
name_tree_init(&hints->tree); name_tree_init(&hints->tree);
/* read root hints */ /* read root hints */
if(!read_root_hints_list(hints, cfg)) if(!read_root_hints_list(hints, cfg)) {
lock_rw_unlock(&hints->lock);
return 0; return 0;
}
/* read stub hints */ /* read stub hints */
if(!read_stubs(hints, cfg)) if(!read_stubs(hints, cfg)) {
lock_rw_unlock(&hints->lock);
return 0; return 0;
}
/* use fallback compiletime root hints */ /* use fallback compiletime root hints */
if(!hints_lookup_root(hints, LDNS_RR_CLASS_IN)) { if(!hints_find_root(hints, LDNS_RR_CLASS_IN, nolock)) {
struct delegpt* dp = compile_time_root_prime(cfg->do_ip4, struct delegpt* dp = compile_time_root_prime(cfg->do_ip4,
cfg->do_ip6); cfg->do_ip6);
verbose(VERB_ALGO, "no config, using builtin root hints."); verbose(VERB_ALGO, "no config, using builtin root hints.");
if(!dp) if(!dp) {
lock_rw_unlock(&hints->lock);
return 0; return 0;
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0)) }
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0)) {
lock_rw_unlock(&hints->lock);
return 0; return 0;
}
} }
name_tree_init_parents(&hints->tree); name_tree_init_parents(&hints->tree);
lock_rw_unlock(&hints->lock);
return 1; return 1;
} }
struct delegpt* struct delegpt*
hints_lookup_root(struct iter_hints* hints, uint16_t qclass) hints_find(struct iter_hints* hints, uint8_t* qname, uint16_t qclass,
int nolock)
{
struct iter_hints_stub *stub;
size_t len;
int has_dp;
int labs = dname_count_size_labels(qname, &len);
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_rdlock(&hints->lock); }
stub = (struct iter_hints_stub*)name_tree_find(&hints->tree,
qname, len, labs, qclass);
has_dp = stub && stub->dp;
if(!has_dp && !nolock) { lock_rw_unlock(&hints->lock); }
return has_dp?stub->dp:NULL;
}
struct delegpt*
hints_find_root(struct iter_hints* hints, uint16_t qclass, int nolock)
{ {
uint8_t rootlab = 0; uint8_t rootlab = 0;
struct iter_hints_stub *stub; return hints_find(hints, &rootlab, qclass, nolock);
stub = (struct iter_hints_stub*)name_tree_find(&hints->tree,
&rootlab, 1, 1, qclass);
if(!stub)
return NULL;
return stub->dp;
} }
struct iter_hints_stub* struct iter_hints_stub*
hints_lookup_stub(struct iter_hints* hints, uint8_t* qname, hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
uint16_t qclass, struct delegpt* cache_dp) uint16_t qclass, struct delegpt* cache_dp, int nolock)
{ {
size_t len; size_t len;
int labs; int labs;
@ -486,14 +512,20 @@ hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
/* first lookup the stub */ /* first lookup the stub */
labs = dname_count_size_labels(qname, &len); labs = dname_count_size_labels(qname, &len);
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_rdlock(&hints->lock); }
r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname, r = (struct iter_hints_stub*)name_tree_lookup(&hints->tree, qname,
len, labs, qclass); len, labs, qclass);
if(!r) return NULL; if(!r) {
if(!nolock) { lock_rw_unlock(&hints->lock); }
return NULL;
}
/* If there is no cache (root prime situation) */ /* If there is no cache (root prime situation) */
if(cache_dp == NULL) { if(cache_dp == NULL) {
if(r->dp->namelabs != 1) if(r->dp->namelabs != 1)
return r; /* no cache dp, use any non-root stub */ return r; /* no cache dp, use any non-root stub */
if(!nolock) { lock_rw_unlock(&hints->lock); }
return NULL; return NULL;
} }
@ -510,12 +542,18 @@ hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
if(dname_strict_subdomain(r->dp->name, r->dp->namelabs, if(dname_strict_subdomain(r->dp->name, r->dp->namelabs,
cache_dp->name, cache_dp->namelabs)) cache_dp->name, cache_dp->namelabs))
return r; /* need to prime this stub */ return r; /* need to prime this stub */
if(!nolock) { lock_rw_unlock(&hints->lock); }
return NULL; return NULL;
} }
int hints_next_root(struct iter_hints* hints, uint16_t* qclass) int hints_next_root(struct iter_hints* hints, uint16_t* qclass, int nolock)
{ {
return name_tree_next_root(&hints->tree, qclass); int ret;
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_rdlock(&hints->lock); }
ret = name_tree_next_root(&hints->tree, qclass);
if(!nolock) { lock_rw_unlock(&hints->lock); }
return ret;
} }
size_t size_t
@ -524,39 +562,52 @@ hints_get_mem(struct iter_hints* hints)
size_t s; size_t s;
struct iter_hints_stub* p; struct iter_hints_stub* p;
if(!hints) return 0; if(!hints) return 0;
lock_rw_rdlock(&hints->lock);
s = sizeof(*hints); s = sizeof(*hints);
RBTREE_FOR(p, struct iter_hints_stub*, &hints->tree) { RBTREE_FOR(p, struct iter_hints_stub*, &hints->tree) {
s += sizeof(*p) + delegpt_get_mem(p->dp); s += sizeof(*p) + delegpt_get_mem(p->dp);
} }
lock_rw_unlock(&hints->lock);
return s; return s;
} }
int int
hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp, hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
int noprime) int noprime, int nolock)
{ {
struct iter_hints_stub *z; struct iter_hints_stub *z;
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&hints->lock); }
if((z=(struct iter_hints_stub*)name_tree_find(&hints->tree, if((z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
dp->name, dp->namelen, dp->namelabs, c)) != NULL) { dp->name, dp->namelen, dp->namelabs, c)) != NULL) {
(void)rbtree_delete(&hints->tree, &z->node); (void)rbtree_delete(&hints->tree, &z->node);
hints_stub_free(z); hints_stub_free(z);
} }
if(!hints_insert(hints, c, dp, noprime)) if(!hints_insert(hints, c, dp, noprime)) {
if(!nolock) { lock_rw_unlock(&hints->lock); }
return 0; return 0;
}
name_tree_init_parents(&hints->tree); name_tree_init_parents(&hints->tree);
if(!nolock) { lock_rw_unlock(&hints->lock); }
return 1; return 1;
} }
void void
hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm) hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm,
int nolock)
{ {
struct iter_hints_stub *z; struct iter_hints_stub *z;
size_t len; size_t len;
int labs = dname_count_size_labels(nm, &len); int labs = dname_count_size_labels(nm, &len);
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&hints->lock); }
if(!(z=(struct iter_hints_stub*)name_tree_find(&hints->tree, if(!(z=(struct iter_hints_stub*)name_tree_find(&hints->tree,
nm, len, labs, c))) nm, len, labs, c))) {
if(!nolock) { lock_rw_unlock(&hints->lock); }
return; /* nothing to do */ return; /* nothing to do */
}
(void)rbtree_delete(&hints->tree, &z->node); (void)rbtree_delete(&hints->tree, &z->node);
hints_stub_free(z); hints_stub_free(z);
name_tree_init_parents(&hints->tree); name_tree_init_parents(&hints->tree);
if(!nolock) { lock_rw_unlock(&hints->lock); }
} }

View file

@ -43,6 +43,7 @@
#ifndef ITERATOR_ITER_HINTS_H #ifndef ITERATOR_ITER_HINTS_H
#define ITERATOR_ITER_HINTS_H #define ITERATOR_ITER_HINTS_H
#include "util/storage/dnstree.h" #include "util/storage/dnstree.h"
#include "util/locks.h"
struct iter_env; struct iter_env;
struct config_file; struct config_file;
struct delegpt; struct delegpt;
@ -51,6 +52,10 @@ struct delegpt;
* Iterator hints structure * Iterator hints structure
*/ */
struct iter_hints { struct iter_hints {
/** lock on the forwards tree.
* When grabbing both this lock and the anchors.lock, this lock
* is grabbed first. */
lock_rw_type lock;
/** /**
* Hints are stored in this tree. Sort order is specially chosen. * Hints are stored in this tree. Sort order is specially chosen.
* first sorted on qclass. Then on dname in nsec-like order, so that * first sorted on qclass. Then on dname in nsec-like order, so that
@ -95,42 +100,70 @@ void hints_delete(struct iter_hints* hints);
int hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg); int hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg);
/** /**
* Find root hints for the given class. * Find hints for the given class.
* The return value is contents of the hints structure.
* Caller should lock and unlock a readlock on the hints structure if nolock
* is set.
* Otherwise caller should unlock the readlock on the hints structure if a
* value was returned.
* @param hints: hint storage. * @param hints: hint storage.
* @param qname: the qname that generated the delegation point.
* @param qclass: class for which root hints are requested. host order. * @param qclass: class for which root hints are requested. host order.
* @param nolock: Skip locking, locking is handled by the caller.
* @return: NULL if no hints, or a ptr to stored hints. * @return: NULL if no hints, or a ptr to stored hints.
*/ */
struct delegpt* hints_lookup_root(struct iter_hints* hints, uint16_t qclass); struct delegpt* hints_find(struct iter_hints* hints, uint8_t* qname,
uint16_t qclass, int nolock);
/**
* Same as hints_lookup, but for the root only.
* @param hints: hint storage.
* @param qclass: class for which root hints are requested. host order.
* @param nolock: Skip locking, locking is handled by the caller.
* @return: NULL if no hints, or a ptr to stored hints.
*/
struct delegpt* hints_find_root(struct iter_hints* hints,
uint16_t qclass, int nolock);
/** /**
* Find next root hints (to cycle through all root hints). * Find next root hints (to cycle through all root hints).
* Handles its own locking unless nolock is set. In that case the caller
* should lock and unlock a readlock on the hints structure.
* @param hints: hint storage * @param hints: hint storage
* @param qclass: class for which root hints are sought. * @param qclass: class for which root hints are sought.
* 0 means give the first available root hints class. * 0 means give the first available root hints class.
* x means, give class x or a higher class if any. * x means, give class x or a higher class if any.
* returns the found class in this variable. * returns the found class in this variable.
* @param nolock: Skip locking, locking is handled by the caller.
* @return true if a root hint class is found. * @return true if a root hint class is found.
* false if not root hint class is found (qclass may have been changed). * false if not root hint class is found (qclass may have been changed).
*/ */
int hints_next_root(struct iter_hints* hints, uint16_t* qclass); int hints_next_root(struct iter_hints* hints, uint16_t* qclass, int nolock);
/** /**
* Given a qname/qclass combination, and the delegation point from the cache * Given a qname/qclass combination, and the delegation point from the cache
* for this qname/qclass, determine if this combination indicates that a * for this qname/qclass, determine if this combination indicates that a
* stub hint exists and must be primed. * stub hint exists and must be primed.
* The return value is contents of the hints structure.
* Caller should lock and unlock a readlock on the hints structure if nolock
* is set.
* Otherwise caller should unlock the readlock on the hints structure if a
* value was returned.
* *
* @param hints: hint storage. * @param hints: hint storage.
* @param qname: The qname that generated the delegation point. * @param qname: The qname that generated the delegation point.
* @param qclass: The qclass that generated the delegation point. * @param qclass: The qclass that generated the delegation point.
* @param dp: The cache generated delegation point. * @param dp: The cache generated delegation point.
* @param nolock: Skip locking, locking is handled by the caller.
* @return: A priming delegation point if there is a stub hint that must * @return: A priming delegation point if there is a stub hint that must
* be primed, otherwise null. * be primed, otherwise null.
*/ */
struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints, struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints,
uint8_t* qname, uint16_t qclass, struct delegpt* dp); uint8_t* qname, uint16_t qclass, struct delegpt* dp, int nolock);
/** /**
* Get memory in use by hints * Get memory in use by hints
* Locks and unlocks the structure.
* @param hints: hint storage. * @param hints: hint storage.
* @return bytes in use * @return bytes in use
*/ */
@ -139,23 +172,30 @@ size_t hints_get_mem(struct iter_hints* hints);
/** /**
* Add stub to hints structure. For external use since it recalcs * Add stub to hints structure. For external use since it recalcs
* the tree parents. * the tree parents.
* Handles its own locking unless nolock is set. In that case the caller
* should lock and unlock a writelock on the hints structure.
* @param hints: the hints data structure * @param hints: the hints data structure
* @param c: class of zone * @param c: class of zone
* @param dp: delegation point with name and target nameservers for new * @param dp: delegation point with name and target nameservers for new
* hints stub. malloced. * hints stub. malloced.
* @param noprime: set noprime option to true or false on new hint stub. * @param noprime: set noprime option to true or false on new hint stub.
* @param nolock: Skip locking, locking is handled by the caller.
* @return false on failure (out of memory); * @return false on failure (out of memory);
*/ */
int hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp, int hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
int noprime); int noprime, int nolock);
/** /**
* Remove stub from hints structure. For external use since it * Remove stub from hints structure. For external use since it
* recalcs the tree parents. * recalcs the tree parents.
* Handles its own locking unless nolock is set. In that case the caller
* should lock and unlock a writelock on the hints structure.
* @param hints: the hints data structure * @param hints: the hints data structure
* @param c: class of stub zone * @param c: class of stub zone
* @param nm: name of stub zone (in uncompressed wireformat). * @param nm: name of stub zone (in uncompressed wireformat).
* @param nolock: Skip locking, locking is handled by the caller.
*/ */
void hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm); void hints_delete_stub(struct iter_hints* hints, uint16_t c,
uint8_t* nm, int nolock);
#endif /* ITERATOR_ITER_HINTS_H */ #endif /* ITERATOR_ITER_HINTS_H */

View file

@ -1284,8 +1284,17 @@ iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
uint16_t* c) uint16_t* c)
{ {
uint16_t c1 = *c, c2 = *c; uint16_t c1 = *c, c2 = *c;
int r1 = hints_next_root(hints, &c1); int r1, r2;
int r2 = forwards_next_root(fwd, &c2); int nolock = 1;
/* prelock both forwards and hints for atomic read. */
lock_rw_rdlock(&fwd->lock);
lock_rw_rdlock(&hints->lock);
r1 = hints_next_root(hints, &c1, nolock);
r2 = forwards_next_root(fwd, &c2, nolock);
lock_rw_unlock(&fwd->lock);
lock_rw_unlock(&hints->lock);
if(!r1 && !r2) /* got none, end of list */ if(!r1 && !r2) /* got none, end of list */
return 0; return 0;
else if(!r1) /* got one, return that */ else if(!r1) /* got one, return that */
@ -1450,15 +1459,21 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp)
int int
iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
uint8_t** retdpname, size_t* retdpnamelen) uint8_t** retdpname, size_t* retdpnamelen, uint8_t* dpname_storage,
size_t dpname_storage_len)
{ {
struct iter_hints_stub *stub; struct iter_hints_stub *stub;
struct delegpt *dp; struct delegpt *dp;
int nolock = 1;
/* Check for stub. */ /* Check for stub. */
/* Lock both forwards and hints for atomic read. */
lock_rw_rdlock(&qstate->env->fwds->lock);
lock_rw_rdlock(&qstate->env->hints->lock);
stub = hints_lookup_stub(qstate->env->hints, qinf->qname, stub = hints_lookup_stub(qstate->env->hints, qinf->qname,
qinf->qclass, NULL); qinf->qclass, NULL, nolock);
dp = forwards_lookup(qstate->env->fwds, qinf->qname, qinf->qclass); dp = forwards_lookup(qstate->env->fwds, qinf->qname, qinf->qclass,
nolock);
/* see if forward or stub is more pertinent */ /* see if forward or stub is more pertinent */
if(stub && stub->dp && dp) { if(stub && stub->dp && dp) {
@ -1472,7 +1487,9 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
/* check stub */ /* check stub */
if (stub != NULL && stub->dp != NULL) { if (stub != NULL && stub->dp != NULL) {
if(stub->dp->no_cache) { int stub_no_cache = stub->dp->no_cache;
lock_rw_unlock(&qstate->env->fwds->lock);
if(stub_no_cache) {
char qname[255+1]; char qname[255+1];
char dpname[255+1]; char dpname[255+1];
dname_str(qinf->qname, qname); dname_str(qinf->qname, qname);
@ -1480,15 +1497,27 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
verbose(VERB_ALGO, "stub for %s %s has no_cache", qname, dpname); verbose(VERB_ALGO, "stub for %s %s has no_cache", qname, dpname);
} }
if(retdpname) { if(retdpname) {
*retdpname = stub->dp->name; if(stub->dp->namelen > dpname_storage_len) {
verbose(VERB_ALGO, "no cache stub dpname too long");
lock_rw_unlock(&qstate->env->hints->lock);
*retdpname = NULL;
*retdpnamelen = 0;
return stub_no_cache;
}
memmove(dpname_storage, stub->dp->name,
stub->dp->namelen);
*retdpname = dpname_storage;
*retdpnamelen = stub->dp->namelen; *retdpnamelen = stub->dp->namelen;
} }
return (stub->dp->no_cache); lock_rw_unlock(&qstate->env->hints->lock);
return stub_no_cache;
} }
/* Check for forward. */ /* Check for forward. */
if (dp) { if (dp) {
if(dp->no_cache) { int dp_no_cache = dp->no_cache;
lock_rw_unlock(&qstate->env->hints->lock);
if(dp_no_cache) {
char qname[255+1]; char qname[255+1];
char dpname[255+1]; char dpname[255+1];
dname_str(qinf->qname, qname); dname_str(qinf->qname, qname);
@ -1496,11 +1525,22 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
verbose(VERB_ALGO, "forward for %s %s has no_cache", qname, dpname); verbose(VERB_ALGO, "forward for %s %s has no_cache", qname, dpname);
} }
if(retdpname) { if(retdpname) {
*retdpname = dp->name; if(dp->namelen > dpname_storage_len) {
verbose(VERB_ALGO, "no cache dpname too long");
lock_rw_unlock(&qstate->env->fwds->lock);
*retdpname = NULL;
*retdpnamelen = 0;
return dp_no_cache;
}
memmove(dpname_storage, dp->name, dp->namelen);
*retdpname = dpname_storage;
*retdpnamelen = dp->namelen; *retdpnamelen = dp->namelen;
} }
return (dp->no_cache); lock_rw_unlock(&qstate->env->fwds->lock);
return dp_no_cache;
} }
lock_rw_unlock(&qstate->env->fwds->lock);
lock_rw_unlock(&qstate->env->hints->lock);
if(retdpname) { if(retdpname) {
*retdpname = NULL; *retdpname = NULL;
*retdpnamelen = 0; *retdpnamelen = 0;

View file

@ -407,10 +407,14 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp);
* Used for NXDOMAIN checks, above that it is an nxdomain from a * Used for NXDOMAIN checks, above that it is an nxdomain from a
* different server and zone. You can pass NULL to not get it. * different server and zone. You can pass NULL to not get it.
* @param retdpnamelen: returns the length of the dpname. * @param retdpnamelen: returns the length of the dpname.
* @param dpname_storage: this is where the dpname buf is stored, if any.
* So that caller can manage the buffer.
* @param dpname_storage_len: size of dpname_storage buffer.
* @return true if no_cache is set in stub or fwd. * @return true if no_cache is set in stub or fwd.
*/ */
int iter_stub_fwd_no_cache(struct module_qstate *qstate, int iter_stub_fwd_no_cache(struct module_qstate *qstate,
struct query_info *qinf, uint8_t** retdpname, size_t* retdpnamelen); struct query_info *qinf, uint8_t** retdpname, size_t* retdpnamelen,
uint8_t* dpname_storage, size_t dpname_storage_len);
/** /**
* Set support for IP4 and IP6 depending on outgoing interfaces * Set support for IP4 and IP6 depending on outgoing interfaces

View file

@ -52,6 +52,7 @@
#include "iterator/iter_priv.h" #include "iterator/iter_priv.h"
#include "validator/val_neg.h" #include "validator/val_neg.h"
#include "services/cache/dns.h" #include "services/cache/dns.h"
#include "services/cache/rrset.h"
#include "services/cache/infra.h" #include "services/cache/infra.h"
#include "services/authzone.h" #include "services/authzone.h"
#include "util/module.h" #include "util/module.h"
@ -678,30 +679,40 @@ errinf_reply(struct module_qstate* qstate, struct iter_qstate* iq)
/** see if last resort is possible - does config allow queries to parent */ /** see if last resort is possible - does config allow queries to parent */
static int static int
can_have_last_resort(struct module_env* env, uint8_t* nm, size_t nmlen, can_have_last_resort(struct module_env* env, uint8_t* nm, size_t ATTR_UNUSED(nmlen),
uint16_t qclass, struct delegpt** retdp) uint16_t qclass, int* have_dp, struct delegpt** retdp,
struct regional* region)
{ {
struct delegpt* fwddp; struct delegpt* dp = NULL;
struct iter_hints_stub* stub; int nolock = 0;
int labs = dname_count_labels(nm);
/* do not process a last resort (the parent side) if a stub /* do not process a last resort (the parent side) if a stub
* or forward is configured, because we do not want to go 'above' * or forward is configured, because we do not want to go 'above'
* the configured servers */ * the configured servers */
if(!dname_is_root(nm) && (stub = (struct iter_hints_stub*) if(!dname_is_root(nm) &&
name_tree_find(&env->hints->tree, nm, nmlen, labs, qclass)) && (dp = hints_find(env->hints, nm, qclass, nolock)) &&
/* has_parent side is turned off for stub_first, where we /* has_parent side is turned off for stub_first, where we
* are allowed to go to the parent */ * are allowed to go to the parent */
stub->dp->has_parent_side_NS) { dp->has_parent_side_NS) {
if(retdp) *retdp = stub->dp; if(retdp) *retdp = delegpt_copy(dp, region);
lock_rw_unlock(&env->hints->lock);
if(have_dp) *have_dp = 1;
return 0; return 0;
} }
if((fwddp = forwards_find(env->fwds, nm, qclass)) && if(dp) {
lock_rw_unlock(&env->hints->lock);
dp = NULL;
}
if((dp = forwards_find(env->fwds, nm, qclass, nolock)) &&
/* has_parent_side is turned off for forward_first, where /* has_parent_side is turned off for forward_first, where
* we are allowed to go to the parent */ * we are allowed to go to the parent */
fwddp->has_parent_side_NS) { dp->has_parent_side_NS) {
if(retdp) *retdp = fwddp; if(retdp) *retdp = delegpt_copy(dp, region);
lock_rw_unlock(&env->fwds->lock);
if(have_dp) *have_dp = 1;
return 0; return 0;
} }
/* lock_() calls are macros that could be nothing, surround in {} */
if(dp) { lock_rw_unlock(&env->fwds->lock); }
return 1; return 1;
} }
@ -877,10 +888,11 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
{ {
struct delegpt* dp; struct delegpt* dp;
struct module_qstate* subq; struct module_qstate* subq;
int nolock = 0;
verbose(VERB_DETAIL, "priming . %s NS", verbose(VERB_DETAIL, "priming . %s NS",
sldns_lookup_by_id(sldns_rr_classes, (int)qclass)? sldns_lookup_by_id(sldns_rr_classes, (int)qclass)?
sldns_lookup_by_id(sldns_rr_classes, (int)qclass)->name:"??"); sldns_lookup_by_id(sldns_rr_classes, (int)qclass)->name:"??");
dp = hints_lookup_root(qstate->env->hints, qclass); dp = hints_find_root(qstate->env->hints, qclass, nolock);
if(!dp) { if(!dp) {
verbose(VERB_ALGO, "Cannot prime due to lack of hints"); verbose(VERB_ALGO, "Cannot prime due to lack of hints");
return 0; return 0;
@ -890,6 +902,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
if(!generate_sub_request((uint8_t*)"\000", 1, LDNS_RR_TYPE_NS, if(!generate_sub_request((uint8_t*)"\000", 1, LDNS_RR_TYPE_NS,
qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE, qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE,
&subq, 0, 0)) { &subq, 0, 0)) {
lock_rw_unlock(&qstate->env->hints->lock);
verbose(VERB_ALGO, "could not prime root"); verbose(VERB_ALGO, "could not prime root");
return 0; return 0;
} }
@ -900,6 +913,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
* copy dp, it is now part of the root prime query. * copy dp, it is now part of the root prime query.
* dp was part of in the fixed hints structure. */ * dp was part of in the fixed hints structure. */
subiq->dp = delegpt_copy(dp, subq->region); subiq->dp = delegpt_copy(dp, subq->region);
lock_rw_unlock(&qstate->env->hints->lock);
if(!subiq->dp) { if(!subiq->dp) {
log_err("out of memory priming root, copydp"); log_err("out of memory priming root, copydp");
fptr_ok(fptr_whitelist_modenv_kill_sub( fptr_ok(fptr_whitelist_modenv_kill_sub(
@ -911,6 +925,8 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
subiq->num_target_queries = 0; subiq->num_target_queries = 0;
subiq->dnssec_expected = iter_indicates_dnssec( subiq->dnssec_expected = iter_indicates_dnssec(
qstate->env, subiq->dp, NULL, subq->qinfo.qclass); qstate->env, subiq->dp, NULL, subq->qinfo.qclass);
} else {
lock_rw_unlock(&qstate->env->hints->lock);
} }
/* this module stops, our submodule starts, and does the query. */ /* this module stops, our submodule starts, and does the query. */
@ -941,18 +957,21 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
struct iter_hints_stub* stub; struct iter_hints_stub* stub;
struct delegpt* stub_dp; struct delegpt* stub_dp;
struct module_qstate* subq; struct module_qstate* subq;
int nolock = 0;
if(!qname) return 0; if(!qname) return 0;
stub = hints_lookup_stub(qstate->env->hints, qname, qclass, iq->dp); stub = hints_lookup_stub(qstate->env->hints, qname, qclass, iq->dp,
nolock);
/* The stub (if there is one) does not need priming. */ /* The stub (if there is one) does not need priming. */
if(!stub) if(!stub) return 0;
return 0;
stub_dp = stub->dp; stub_dp = stub->dp;
/* if we have an auth_zone dp, and stub is equal, don't prime stub /* if we have an auth_zone dp, and stub is equal, don't prime stub
* yet, unless we want to fallback and avoid the auth_zone */ * yet, unless we want to fallback and avoid the auth_zone */
if(!iq->auth_zone_avoid && iq->dp && iq->dp->auth_dp && if(!iq->auth_zone_avoid && iq->dp && iq->dp->auth_dp &&
query_dname_compare(iq->dp->name, stub_dp->name) == 0) query_dname_compare(iq->dp->name, stub_dp->name) == 0) {
lock_rw_unlock(&qstate->env->hints->lock);
return 0; return 0;
}
/* is it a noprime stub (always use) */ /* is it a noprime stub (always use) */
if(stub->noprime) { if(stub->noprime) {
@ -961,13 +980,14 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
/* copy the dp out of the fixed hints structure, so that /* copy the dp out of the fixed hints structure, so that
* it can be changed when servicing this query */ * it can be changed when servicing this query */
iq->dp = delegpt_copy(stub_dp, qstate->region); iq->dp = delegpt_copy(stub_dp, qstate->region);
lock_rw_unlock(&qstate->env->hints->lock);
if(!iq->dp) { if(!iq->dp) {
log_err("out of memory priming stub"); log_err("out of memory priming stub");
errinf(qstate, "malloc failure, priming stub"); errinf(qstate, "malloc failure, priming stub");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return 1; /* return 1 to make module stop, with error */ return 1; /* return 1 to make module stop, with error */
} }
log_nametypeclass(VERB_DETAIL, "use stub", stub_dp->name, log_nametypeclass(VERB_DETAIL, "use stub", iq->dp->name,
LDNS_RR_TYPE_NS, qclass); LDNS_RR_TYPE_NS, qclass);
return r; return r;
} }
@ -981,6 +1001,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
if(!generate_sub_request(stub_dp->name, stub_dp->namelen, if(!generate_sub_request(stub_dp->name, stub_dp->namelen,
LDNS_RR_TYPE_NS, qclass, qstate, id, iq, LDNS_RR_TYPE_NS, qclass, qstate, id, iq,
QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0, 0)) { QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0, 0)) {
lock_rw_unlock(&qstate->env->hints->lock);
verbose(VERB_ALGO, "could not prime stub"); verbose(VERB_ALGO, "could not prime stub");
errinf(qstate, "could not generate lookup for stub prime"); errinf(qstate, "could not generate lookup for stub prime");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
@ -993,6 +1014,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
/* Set the initial delegation point to the hint. */ /* Set the initial delegation point to the hint. */
/* make copy to avoid use of stub dp by different qs/threads */ /* make copy to avoid use of stub dp by different qs/threads */
subiq->dp = delegpt_copy(stub_dp, subq->region); subiq->dp = delegpt_copy(stub_dp, subq->region);
lock_rw_unlock(&qstate->env->hints->lock);
if(!subiq->dp) { if(!subiq->dp) {
log_err("out of memory priming stub, copydp"); log_err("out of memory priming stub, copydp");
fptr_ok(fptr_whitelist_modenv_kill_sub( fptr_ok(fptr_whitelist_modenv_kill_sub(
@ -1009,6 +1031,8 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
subiq->wait_priming_stub = 1; subiq->wait_priming_stub = 1;
subiq->dnssec_expected = iter_indicates_dnssec( subiq->dnssec_expected = iter_indicates_dnssec(
qstate->env, subiq->dp, NULL, subq->qinfo.qclass); qstate->env, subiq->dp, NULL, subq->qinfo.qclass);
} else {
lock_rw_unlock(&qstate->env->hints->lock);
} }
/* this module stops, our submodule starts, and does the query. */ /* this module stops, our submodule starts, and does the query. */
@ -1181,7 +1205,7 @@ generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id)
if(iq->depth == ie->max_dependency_depth) if(iq->depth == ie->max_dependency_depth)
return; return;
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen,
iq->qchase.qclass, NULL)) iq->qchase.qclass, NULL, NULL, NULL))
return; return;
/* is this query the same as the nscheck? */ /* is this query the same as the nscheck? */
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS && if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS &&
@ -1294,6 +1318,7 @@ forward_request(struct module_qstate* qstate, struct iter_qstate* iq)
struct delegpt* dp; struct delegpt* dp;
uint8_t* delname = iq->qchase.qname; uint8_t* delname = iq->qchase.qname;
size_t delnamelen = iq->qchase.qname_len; size_t delnamelen = iq->qchase.qname_len;
int nolock = 0;
if(iq->refetch_glue && iq->dp) { if(iq->refetch_glue && iq->dp) {
delname = iq->dp->name; delname = iq->dp->name;
delnamelen = iq->dp->namelen; delnamelen = iq->dp->namelen;
@ -1302,12 +1327,13 @@ forward_request(struct module_qstate* qstate, struct iter_qstate* iq)
if( (iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue) if( (iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue)
&& !dname_is_root(iq->qchase.qname)) && !dname_is_root(iq->qchase.qname))
dname_remove_label(&delname, &delnamelen); dname_remove_label(&delname, &delnamelen);
dp = forwards_lookup(qstate->env->fwds, delname, iq->qchase.qclass); dp = forwards_lookup(qstate->env->fwds, delname, iq->qchase.qclass,
if(!dp) nolock);
return 0; if(!dp) return 0;
/* send recursion desired to forward addr */ /* send recursion desired to forward addr */
iq->chase_flags |= BIT_RD; iq->chase_flags |= BIT_RD;
iq->dp = delegpt_copy(dp, qstate->region); iq->dp = delegpt_copy(dp, qstate->region);
lock_rw_unlock(&qstate->env->fwds->lock);
/* iq->dp checked by caller */ /* iq->dp checked by caller */
verbose(VERB_ALGO, "forwarding request"); verbose(VERB_ALGO, "forwarding request");
return 1; return 1;
@ -1335,6 +1361,7 @@ static int
processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
struct iter_env* ie, int id) struct iter_env* ie, int id)
{ {
uint8_t dpname_storage[LDNS_MAX_DOMAINLEN+1];
uint8_t* delname, *dpname=NULL; uint8_t* delname, *dpname=NULL;
size_t delnamelen, dpnamelen=0; size_t delnamelen, dpnamelen=0;
struct dns_msg* msg = NULL; struct dns_msg* msg = NULL;
@ -1381,7 +1408,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
if (iq->refetch_glue && if (iq->refetch_glue &&
iq->dp && iq->dp &&
!can_have_last_resort(qstate->env, iq->dp->name, !can_have_last_resort(qstate->env, iq->dp->name,
iq->dp->namelen, iq->qchase.qclass, NULL)) { iq->dp->namelen, iq->qchase.qclass, NULL, NULL, NULL)) {
iq->refetch_glue = 0; iq->refetch_glue = 0;
} }
@ -1390,7 +1417,60 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
/* This either results in a query restart (CNAME cache response), a /* This either results in a query restart (CNAME cache response), a
* terminating response (ANSWER), or a cache miss (null). */ * terminating response (ANSWER), or a cache miss (null). */
if (iter_stub_fwd_no_cache(qstate, &iq->qchase, &dpname, &dpnamelen)) { /* Check RPZ for override */
if(qstate->env->auth_zones) {
/* apply rpz qname triggers, like after cname */
struct dns_msg* forged_response =
rpz_callback_from_iterator_cname(qstate, iq);
if(forged_response) {
uint8_t* sname = 0;
size_t slen = 0;
int count = 0;
while(forged_response && reply_find_rrset_section_an(
forged_response->rep, iq->qchase.qname,
iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
iq->qchase.qclass) &&
iq->qchase.qtype != LDNS_RR_TYPE_CNAME &&
count++ < ie->max_query_restarts) {
/* another cname to follow */
if(!handle_cname_response(qstate, iq, forged_response,
&sname, &slen)) {
errinf(qstate, "malloc failure, CNAME info");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->qchase.qname = sname;
iq->qchase.qname_len = slen;
forged_response =
rpz_callback_from_iterator_cname(qstate, iq);
}
if(forged_response != NULL) {
qstate->ext_state[id] = module_finished;
qstate->return_rcode = LDNS_RCODE_NOERROR;
qstate->return_msg = forged_response;
iq->response = forged_response;
next_state(iq, FINISHED_STATE);
if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
log_err("rpz: after cached cname, prepend rrsets: out of memory");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
qstate->return_msg->qinfo = qstate->qinfo;
return 0;
}
/* Follow the CNAME response */
iq->dp = NULL;
iq->refetch_glue = 0;
iq->query_restart_count++;
iq->sent_count = 0;
iq->dp_target_count = 0;
sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
if(qstate->env->cfg->qname_minimisation)
iq->minimisation_state = INIT_MINIMISE_STATE;
return next_state(iq, INIT_REQUEST_STATE);
}
}
if (iter_stub_fwd_no_cache(qstate, &iq->qchase, &dpname, &dpnamelen,
dpname_storage, sizeof(dpname_storage))) {
/* Asked to not query cache. */ /* Asked to not query cache. */
verbose(VERB_ALGO, "no-cache set, going to the network"); verbose(VERB_ALGO, "no-cache set, going to the network");
qstate->no_cache_lookup = 1; qstate->no_cache_lookup = 1;
@ -1449,39 +1529,6 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
} }
iq->qchase.qname = sname; iq->qchase.qname = sname;
iq->qchase.qname_len = slen; iq->qchase.qname_len = slen;
if(qstate->env->auth_zones) {
/* apply rpz qname triggers after cname */
struct dns_msg* forged_response =
rpz_callback_from_iterator_cname(qstate, iq);
while(forged_response && reply_find_rrset_section_an(
forged_response->rep, iq->qchase.qname,
iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
iq->qchase.qclass)) {
/* another cname to follow */
if(!handle_cname_response(qstate, iq, forged_response,
&sname, &slen)) {
errinf(qstate, "malloc failure, CNAME info");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->qchase.qname = sname;
iq->qchase.qname_len = slen;
forged_response =
rpz_callback_from_iterator_cname(qstate, iq);
}
if(forged_response != NULL) {
qstate->ext_state[id] = module_finished;
qstate->return_rcode = LDNS_RCODE_NOERROR;
qstate->return_msg = forged_response;
iq->response = forged_response;
next_state(iq, FINISHED_STATE);
if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
log_err("rpz: after cached cname, prepend rrsets: out of memory");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
qstate->return_msg->qinfo = qstate->qinfo;
return 0;
}
}
/* This *is* a query restart, even if it is a cheap /* This *is* a query restart, even if it is a cheap
* one. */ * one. */
iq->dp = NULL; iq->dp = NULL;
@ -1494,7 +1541,6 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
iq->minimisation_state = INIT_MINIMISE_STATE; iq->minimisation_state = INIT_MINIMISE_STATE;
return next_state(iq, INIT_REQUEST_STATE); return next_state(iq, INIT_REQUEST_STATE);
} }
/* if from cache, NULL, else insert 'cache IP' len=0 */ /* if from cache, NULL, else insert 'cache IP' len=0 */
if(qstate->reply_origin) if(qstate->reply_origin)
sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region); sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
@ -1555,7 +1601,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
} }
if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue || if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue ||
(iq->qchase.qtype == LDNS_RR_TYPE_NS && qstate->prefetch_leeway (iq->qchase.qtype == LDNS_RR_TYPE_NS && qstate->prefetch_leeway
&& can_have_last_resort(qstate->env, delname, delnamelen, iq->qchase.qclass, NULL))) { && can_have_last_resort(qstate->env, delname, delnamelen, iq->qchase.qclass, NULL, NULL, NULL))) {
/* remove first label from delname, root goes to hints, /* remove first label from delname, root goes to hints,
* but only to fetch glue, not for qtype=DS. */ * but only to fetch glue, not for qtype=DS. */
/* also when prefetching an NS record, fetch it again from /* also when prefetching an NS record, fetch it again from
@ -1584,6 +1630,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
* root priming situation. */ * root priming situation. */
if(iq->dp == NULL) { if(iq->dp == NULL) {
int r; int r;
int nolock = 0;
/* if under auth zone, no prime needed */ /* if under auth zone, no prime needed */
if(!auth_zone_delegpt(qstate, iq, delname, delnamelen)) if(!auth_zone_delegpt(qstate, iq, delname, delnamelen))
return error_response(qstate, id, return error_response(qstate, id,
@ -1598,11 +1645,12 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
else if(r) else if(r)
return 0; /* stub prime request made */ return 0; /* stub prime request made */
if(forwards_lookup_root(qstate->env->fwds, if(forwards_lookup_root(qstate->env->fwds,
iq->qchase.qclass)) { iq->qchase.qclass, nolock)) {
lock_rw_unlock(&qstate->env->fwds->lock);
/* forward zone root, no root prime needed */ /* forward zone root, no root prime needed */
/* fill in some dp - safety belt */ /* fill in some dp - safety belt */
iq->dp = hints_lookup_root(qstate->env->hints, iq->dp = hints_find_root(qstate->env->hints,
iq->qchase.qclass); iq->qchase.qclass, nolock);
if(!iq->dp) { if(!iq->dp) {
log_err("internal error: no hints dp"); log_err("internal error: no hints dp");
errinf(qstate, "no hints for this class"); errinf(qstate, "no hints for this class");
@ -1610,6 +1658,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
LDNS_RCODE_SERVFAIL); LDNS_RCODE_SERVFAIL);
} }
iq->dp = delegpt_copy(iq->dp, qstate->region); iq->dp = delegpt_copy(iq->dp, qstate->region);
lock_rw_unlock(&qstate->env->hints->lock);
if(!iq->dp) { if(!iq->dp) {
log_err("out of memory in safety belt"); log_err("out of memory in safety belt");
errinf(qstate, "malloc failure, in safety belt"); errinf(qstate, "malloc failure, in safety belt");
@ -1649,15 +1698,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags, if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags,
iq->dp, ie->supports_ipv4, ie->supports_ipv6, iq->dp, ie->supports_ipv4, ie->supports_ipv6,
ie->use_nat64)) { ie->use_nat64)) {
struct delegpt* retdp = NULL; int have_dp = 0;
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &retdp)) { if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &have_dp, &iq->dp, qstate->region)) {
if(retdp) { if(have_dp) {
verbose(VERB_QUERY, "cache has stub " verbose(VERB_QUERY, "cache has stub "
"or fwd but no addresses, " "or fwd but no addresses, "
"fallback to config"); "fallback to config");
iq->dp = delegpt_copy(retdp, if(have_dp && !iq->dp) {
qstate->region);
if(!iq->dp) {
log_err("out of memory in " log_err("out of memory in "
"stub/fwd fallback"); "stub/fwd fallback");
errinf(qstate, "malloc failure, for fallback to config"); errinf(qstate, "malloc failure, for fallback to config");
@ -1677,10 +1724,11 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
} }
if(dname_is_root(iq->dp->name)) { if(dname_is_root(iq->dp->name)) {
/* use safety belt */ /* use safety belt */
int nolock = 0;
verbose(VERB_QUERY, "Cache has root NS but " verbose(VERB_QUERY, "Cache has root NS but "
"no addresses. Fallback to the safety belt."); "no addresses. Fallback to the safety belt.");
iq->dp = hints_lookup_root(qstate->env->hints, iq->dp = hints_find_root(qstate->env->hints,
iq->qchase.qclass); iq->qchase.qclass, nolock);
/* note deleg_msg is from previous lookup, /* note deleg_msg is from previous lookup,
* but RD is on, so it is not used */ * but RD is on, so it is not used */
if(!iq->dp) { if(!iq->dp) {
@ -1689,6 +1737,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
LDNS_RCODE_REFUSED); LDNS_RCODE_REFUSED);
} }
iq->dp = delegpt_copy(iq->dp, qstate->region); iq->dp = delegpt_copy(iq->dp, qstate->region);
lock_rw_unlock(&qstate->env->hints->lock);
if(!iq->dp) { if(!iq->dp) {
log_err("out of memory in safety belt"); log_err("out of memory in safety belt");
errinf(qstate, "malloc failure, in safety belt, for root"); errinf(qstate, "malloc failure, in safety belt, for root");
@ -1744,6 +1793,7 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
delnamelen = iq->qchase.qname_len; delnamelen = iq->qchase.qname_len;
if(iq->refetch_glue) { if(iq->refetch_glue) {
struct iter_hints_stub* stub; struct iter_hints_stub* stub;
int nolock = 0;
if(!iq->dp) { if(!iq->dp) {
log_err("internal or malloc fail: no dp for refetch"); log_err("internal or malloc fail: no dp for refetch");
errinf(qstate, "malloc failure, no delegation info"); errinf(qstate, "malloc failure, no delegation info");
@ -1753,12 +1803,14 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
* this is above stub without stub-first. */ * this is above stub without stub-first. */
stub = hints_lookup_stub( stub = hints_lookup_stub(
qstate->env->hints, iq->qchase.qname, iq->qchase.qclass, qstate->env->hints, iq->qchase.qname, iq->qchase.qclass,
iq->dp); iq->dp, nolock);
if(!stub || !stub->dp->has_parent_side_NS || if(!stub || !stub->dp->has_parent_side_NS ||
dname_subdomain_c(iq->dp->name, stub->dp->name)) { dname_subdomain_c(iq->dp->name, stub->dp->name)) {
delname = iq->dp->name; delname = iq->dp->name;
delnamelen = iq->dp->namelen; delnamelen = iq->dp->namelen;
} }
/* lock_() calls are macros that could be nothing, surround in {} */
if(stub) { lock_rw_unlock(&qstate->env->hints->lock); }
} }
if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue) { if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue) {
if(!dname_is_root(delname)) if(!dname_is_root(delname))
@ -2062,7 +2114,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
log_assert(iq->dp); log_assert(iq->dp);
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen,
iq->qchase.qclass, NULL)) { iq->qchase.qclass, NULL, NULL, NULL)) {
/* fail -- no more targets, no more hope of targets, no hope /* fail -- no more targets, no more hope of targets, no hope
* of a response. */ * of a response. */
errinf(qstate, "all the configured stub or forward servers failed,"); errinf(qstate, "all the configured stub or forward servers failed,");
@ -2072,21 +2124,24 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
} }
if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) { if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) {
struct delegpt* p = hints_lookup_root(qstate->env->hints, struct delegpt* dp;
iq->qchase.qclass); int nolock = 0;
if(p) { dp = hints_find_root(qstate->env->hints,
iq->qchase.qclass, nolock);
if(dp) {
struct delegpt_addr* a; struct delegpt_addr* a;
iq->chase_flags &= ~BIT_RD; /* go to authorities */ iq->chase_flags &= ~BIT_RD; /* go to authorities */
for(ns = p->nslist; ns; ns=ns->next) { for(ns = dp->nslist; ns; ns=ns->next) {
(void)delegpt_add_ns(iq->dp, qstate->region, (void)delegpt_add_ns(iq->dp, qstate->region,
ns->name, ns->lame, ns->tls_auth_name, ns->name, ns->lame, ns->tls_auth_name,
ns->port); ns->port);
} }
for(a = p->target_list; a; a=a->next_target) { for(a = dp->target_list; a; a=a->next_target) {
(void)delegpt_add_addr(iq->dp, qstate->region, (void)delegpt_add_addr(iq->dp, qstate->region,
&a->addr, a->addrlen, a->bogus, &a->addr, a->addrlen, a->bogus,
a->lame, a->tls_auth_name, -1, NULL); a->lame, a->tls_auth_name, -1, NULL);
} }
lock_rw_unlock(&qstate->env->hints->lock);
} }
iq->dp->has_parent_side_NS = 1; iq->dp->has_parent_side_NS = 1;
} else if(!iq->dp->has_parent_side_NS) { } else if(!iq->dp->has_parent_side_NS) {
@ -2164,7 +2219,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
if( ((ie->supports_ipv6 && !ns->done_pside6) || if( ((ie->supports_ipv6 && !ns->done_pside6) ||
((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4)) && ((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4)) &&
!can_have_last_resort(qstate->env, ns->name, ns->namelen, !can_have_last_resort(qstate->env, ns->name, ns->namelen,
iq->qchase.qclass, NULL)) { iq->qchase.qclass, NULL, NULL, NULL)) {
log_nametypeclass(VERB_ALGO, "cannot pside lookup ns " log_nametypeclass(VERB_ALGO, "cannot pside lookup ns "
"because it is also a stub/forward,", "because it is also a stub/forward,",
ns->name, LDNS_RR_TYPE_NS, iq->qchase.qclass); ns->name, LDNS_RR_TYPE_NS, iq->qchase.qclass);
@ -2746,8 +2801,51 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
delegpt_add_unused_targets(iq->dp); delegpt_add_unused_targets(iq->dp);
if(qstate->env->auth_zones) { if(qstate->env->auth_zones) {
/* apply rpz triggers at query time */ uint8_t* sname = NULL;
size_t snamelen = 0;
/* apply rpz triggers at query time; nameserver IP and dname */
struct dns_msg* forged_response_after_cname;
struct dns_msg* forged_response = rpz_callback_from_iterator_module(qstate, iq); struct dns_msg* forged_response = rpz_callback_from_iterator_module(qstate, iq);
int count = 0;
while(forged_response && reply_find_rrset_section_an(
forged_response->rep, iq->qchase.qname,
iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
iq->qchase.qclass) &&
iq->qchase.qtype != LDNS_RR_TYPE_CNAME &&
count++ < ie->max_query_restarts) {
/* another cname to follow */
if(!handle_cname_response(qstate, iq, forged_response,
&sname, &snamelen)) {
errinf(qstate, "malloc failure, CNAME info");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->qchase.qname = sname;
iq->qchase.qname_len = snamelen;
forged_response_after_cname =
rpz_callback_from_iterator_cname(qstate, iq);
if(forged_response_after_cname) {
forged_response = forged_response_after_cname;
} else {
/* Follow the CNAME with a query restart */
iq->deleg_msg = NULL;
iq->dp = NULL;
iq->dsns_point = NULL;
iq->auth_zone_response = 0;
iq->refetch_glue = 0;
iq->query_restart_count++;
iq->sent_count = 0;
iq->dp_target_count = 0;
if(qstate->env->cfg->qname_minimisation)
iq->minimisation_state = INIT_MINIMISE_STATE;
outbound_list_clear(&iq->outlist);
iq->num_current_queries = 0;
fptr_ok(fptr_whitelist_modenv_detach_subs(
qstate->env->detach_subs));
(*qstate->env->detach_subs)(qstate);
iq->num_target_queries = 0;
return next_state(iq, INIT_REQUEST_STATE);
}
}
if(forged_response != NULL) { if(forged_response != NULL) {
qstate->ext_state[id] = module_finished; qstate->ext_state[id] = module_finished;
qstate->return_rcode = LDNS_RCODE_NOERROR; qstate->return_rcode = LDNS_RCODE_NOERROR;
@ -3082,7 +3180,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* DNAME to a subdomain loop; do not recurse */ /* DNAME to a subdomain loop; do not recurse */
type = RESPONSE_TYPE_ANSWER; type = RESPONSE_TYPE_ANSWER;
} }
} else if(type == RESPONSE_TYPE_CNAME && }
if(type == RESPONSE_TYPE_CNAME &&
iq->qchase.qtype == LDNS_RR_TYPE_CNAME && iq->qchase.qtype == LDNS_RR_TYPE_CNAME &&
iq->minimisation_state == MINIMISE_STATE && iq->minimisation_state == MINIMISE_STATE &&
query_dname_compare(iq->qchase.qname, iq->qinfo_out.qname) == 0) { query_dname_compare(iq->qchase.qname, iq->qinfo_out.qname) == 0) {
@ -3193,6 +3292,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
} }
return final_state(iq); return final_state(iq);
} else if(type == RESPONSE_TYPE_REFERRAL) { } else if(type == RESPONSE_TYPE_REFERRAL) {
struct delegpt* old_dp = NULL;
/* REFERRAL type responses get a reset of the /* REFERRAL type responses get a reset of the
* delegation point, and back to the QUERYTARGETS_STATE. */ * delegation point, and back to the QUERYTARGETS_STATE. */
verbose(VERB_DETAIL, "query response was REFERRAL"); verbose(VERB_DETAIL, "query response was REFERRAL");
@ -3244,6 +3344,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* Reset the event state, setting the current delegation /* Reset the event state, setting the current delegation
* point to the referral. */ * point to the referral. */
iq->deleg_msg = iq->response; iq->deleg_msg = iq->response;
/* Keep current delegation point for label comparison */
old_dp = iq->dp;
iq->dp = delegpt_from_message(iq->response, qstate->region); iq->dp = delegpt_from_message(iq->response, qstate->region);
if (qstate->env->cfg->qname_minimisation) if (qstate->env->cfg->qname_minimisation)
iq->minimisation_state = INIT_MINIMISE_STATE; iq->minimisation_state = INIT_MINIMISE_STATE;
@ -3251,6 +3353,20 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
errinf(qstate, "malloc failure, for delegation point"); errinf(qstate, "malloc failure, for delegation point");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL); return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
} }
if(old_dp->namelabs + 1 < iq->dp->namelabs) {
/* We got a grandchild delegation (more than one label
* difference) than expected. Check for in-between
* delegations in the cache and remove them.
* They could prove problematic when they expire
* and rrset_expired_above() encounters them during
* delegation cache lookups. */
uint8_t* qname = iq->dp->name;
size_t qnamelen = iq->dp->namelen;
rrset_cache_remove_above(qstate->env->rrset_cache,
&qname, &qnamelen, LDNS_RR_TYPE_NS,
iq->qchase.qclass, *qstate->env->now,
old_dp->name, old_dp->namelen);
}
if(!cache_fill_missing(qstate->env, iq->qchase.qclass, if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
qstate->region, iq->dp)) { qstate->region, iq->dp)) {
errinf(qstate, "malloc failure, copy extra info into delegation point"); errinf(qstate, "malloc failure, copy extra info into delegation point");
@ -3341,10 +3457,13 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* apply rpz qname triggers after cname */ /* apply rpz qname triggers after cname */
struct dns_msg* forged_response = struct dns_msg* forged_response =
rpz_callback_from_iterator_cname(qstate, iq); rpz_callback_from_iterator_cname(qstate, iq);
int count = 0;
while(forged_response && reply_find_rrset_section_an( while(forged_response && reply_find_rrset_section_an(
forged_response->rep, iq->qchase.qname, forged_response->rep, iq->qchase.qname,
iq->qchase.qname_len, LDNS_RR_TYPE_CNAME, iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
iq->qchase.qclass)) { iq->qchase.qclass) &&
iq->qchase.qtype != LDNS_RR_TYPE_CNAME &&
count++ < ie->max_query_restarts) {
/* another cname to follow */ /* another cname to follow */
if(!handle_cname_response(qstate, iq, forged_response, if(!handle_cname_response(qstate, iq, forged_response,
&sname, &snamelen)) { &sname, &snamelen)) {
@ -3926,17 +4045,9 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
!qstate->env->cfg->val_log_squelch) { !qstate->env->cfg->val_log_squelch) {
char* err_str = errinf_to_str_misc(qstate); char* err_str = errinf_to_str_misc(qstate);
if(err_str) { if(err_str) {
size_t err_str_len = strlen(err_str);
verbose(VERB_ALGO, "iterator EDE: %s", err_str); verbose(VERB_ALGO, "iterator EDE: %s", err_str);
/* allocate space and store the error iq->response->rep->reason_bogus_str = err_str;
* 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 */ /* we have finished processing this query */

View file

@ -53,6 +53,8 @@
#include "util/storage/slabhash.h" #include "util/storage/slabhash.h"
#include "util/edns.h" #include "util/edns.h"
#include "sldns/sbuffer.h" #include "sldns/sbuffer.h"
#include "iterator/iter_fwd.h"
#include "iterator/iter_hints.h"
int int
context_finalize(struct ub_ctx* ctx) context_finalize(struct ub_ctx* ctx)
@ -85,6 +87,12 @@ context_finalize(struct ub_ctx* ctx)
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz, if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz,
ctx->env, &ctx->mods)) ctx->env, &ctx->mods))
return UB_INITFAIL; return UB_INITFAIL;
if(!(ctx->env->fwds = forwards_create()) ||
!forwards_apply_cfg(ctx->env->fwds, cfg))
return UB_INITFAIL;
if(!(ctx->env->hints = hints_create()) ||
!hints_apply_cfg(ctx->env->hints, cfg))
return UB_INITFAIL;
if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg)) if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg))
return UB_INITFAIL; return UB_INITFAIL;
if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size, if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,

View file

@ -66,6 +66,8 @@
#include "services/authzone.h" #include "services/authzone.h"
#include "services/listen_dnsport.h" #include "services/listen_dnsport.h"
#include "sldns/sbuffer.h" #include "sldns/sbuffer.h"
#include "iterator/iter_fwd.h"
#include "iterator/iter_hints.h"
#ifdef HAVE_PTHREAD #ifdef HAVE_PTHREAD
#include <signal.h> #include <signal.h>
#endif #endif
@ -171,6 +173,7 @@ static struct ub_ctx* ub_ctx_create_nopipe(void)
ctx->env->worker = NULL; ctx->env->worker = NULL;
ctx->env->need_to_validate = 0; ctx->env->need_to_validate = 0;
modstack_init(&ctx->mods); modstack_init(&ctx->mods);
ctx->env->modstack = &ctx->mods;
rbtree_init(&ctx->queries, &context_query_cmp); rbtree_init(&ctx->queries, &context_query_cmp);
return ctx; return ctx;
} }
@ -379,6 +382,8 @@ ub_ctx_delete(struct ub_ctx* ctx)
config_delete(ctx->env->cfg); config_delete(ctx->env->cfg);
edns_known_options_delete(ctx->env); edns_known_options_delete(ctx->env);
edns_strings_delete(ctx->env->edns_strings); edns_strings_delete(ctx->env->edns_strings);
forwards_delete(ctx->env->fwds);
hints_delete(ctx->env->hints);
auth_zones_delete(ctx->env->auth_zones); auth_zones_delete(ctx->env->auth_zones);
free(ctx->env); free(ctx->env);
} }

View file

@ -70,8 +70,6 @@
#include "util/data/msgreply.h" #include "util/data/msgreply.h"
#include "util/data/msgencode.h" #include "util/data/msgencode.h"
#include "util/tube.h" #include "util/tube.h"
#include "iterator/iter_fwd.h"
#include "iterator/iter_hints.h"
#include "sldns/sbuffer.h" #include "sldns/sbuffer.h"
#include "sldns/str2wire.h" #include "sldns/str2wire.h"
#ifdef USE_DNSTAP #ifdef USE_DNSTAP
@ -100,8 +98,6 @@ libworker_delete_env(struct libworker* w)
!w->is_bg || w->is_bg_thread); !w->is_bg || w->is_bg_thread);
sldns_buffer_free(w->env->scratch_buffer); sldns_buffer_free(w->env->scratch_buffer);
regional_destroy(w->env->scratch); regional_destroy(w->env->scratch);
forwards_delete(w->env->fwds);
hints_delete(w->env->hints);
ub_randfree(w->env->rnd); ub_randfree(w->env->rnd);
free(w->env); free(w->env);
} }
@ -159,30 +155,19 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
} }
w->env->scratch = regional_create_custom(cfg->msg_buffer_size); w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
w->env->fwds = forwards_create();
if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) {
forwards_delete(w->env->fwds);
w->env->fwds = NULL;
}
w->env->hints = hints_create();
if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) {
hints_delete(w->env->hints);
w->env->hints = NULL;
}
#ifdef HAVE_SSL #ifdef HAVE_SSL
w->sslctx = connect_sslctx_create(NULL, NULL, w->sslctx = connect_sslctx_create(NULL, NULL,
cfg->tls_cert_bundle, cfg->tls_win_cert); cfg->tls_cert_bundle, cfg->tls_win_cert);
if(!w->sslctx) { if(!w->sslctx) {
/* to make the setup fail after unlock */ /* to make the setup fail after unlock */
hints_delete(w->env->hints); sldns_buffer_free(w->env->scratch_buffer);
w->env->hints = NULL; w->env->scratch_buffer = NULL;
} }
#endif #endif
if(!w->is_bg || w->is_bg_thread) { if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock); lock_basic_unlock(&ctx->cfglock);
} }
if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds || if(!w->env->scratch || !w->env->scratch_buffer) {
!w->env->hints) {
libworker_delete(w); libworker_delete(w);
return NULL; return NULL;
} }

View file

@ -2152,6 +2152,16 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c)
if(az->rpz_first) if(az->rpz_first)
az->rpz_first->rpz_az_prev = z; az->rpz_first->rpz_az_prev = z;
az->rpz_first = z; az->rpz_first = z;
} else if(c->isrpz && z->rpz) {
if(!rpz_config(z->rpz, c)) {
log_err("Could not change rpz config");
if(x) {
lock_basic_unlock(&x->lock);
}
lock_rw_unlock(&z->lock);
lock_rw_unlock(&az->rpz_lock);
return 0;
}
} }
if(c->isrpz) { if(c->isrpz) {
lock_rw_unlock(&az->rpz_lock); lock_rw_unlock(&az->rpz_lock);

View file

@ -193,46 +193,6 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc); slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc);
} }
/** see if an rrset is expired above the qname, return upper qname. */
static int
rrset_expired_above(struct module_env* env, uint8_t** qname, size_t* qnamelen,
uint16_t searchtype, uint16_t qclass, time_t now, uint8_t* expiretop,
size_t expiretoplen)
{
struct ub_packed_rrset_key *rrset;
uint8_t lablen;
while(*qnamelen > 0) {
/* look one label higher */
lablen = **qname;
*qname += lablen + 1;
*qnamelen -= lablen + 1;
if(*qnamelen <= 0)
break;
/* looks up with a time of 0, to see expired entries */
if((rrset = rrset_cache_lookup(env->rrset_cache, *qname,
*qnamelen, searchtype, qclass, 0, 0, 0))) {
struct packed_rrset_data* data =
(struct packed_rrset_data*)rrset->entry.data;
if(now > data->ttl) {
/* it is expired, this is not wanted */
lock_rw_unlock(&rrset->entry.lock);
log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass);
return 1;
}
/* it is not expired, continue looking */
lock_rw_unlock(&rrset->entry.lock);
}
/* do not look above the expiretop. */
if(expiretop && *qnamelen == expiretoplen &&
query_dname_compare(*qname, expiretop)==0)
break;
}
return 0;
}
/** find closest NS or DNAME and returns the rrset (locked) */ /** find closest NS or DNAME and returns the rrset (locked) */
static struct ub_packed_rrset_key* static struct ub_packed_rrset_key*
find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen, find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
@ -266,12 +226,12 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
/* check for expiry, but we have to let go of the rrset /* check for expiry, but we have to let go of the rrset
* for the lock ordering */ * for the lock ordering */
lock_rw_unlock(&rrset->entry.lock); lock_rw_unlock(&rrset->entry.lock);
/* the expired_above function always takes off one /* the rrset_cache_expired_above function always takes
* label (if qnamelen>0) and returns the final qname * off one label (if qnamelen>0) and returns the final
* where it searched, so we can continue from there * qname where it searched, so we can continue from
* turning the O N*N search into O N. */ * there turning the O N*N search into O N. */
if(!rrset_expired_above(env, &qname, &qnamelen, if(!rrset_cache_expired_above(env->rrset_cache, &qname,
searchtype, qclass, now, expiretop, &qnamelen, searchtype, qclass, now, expiretop,
expiretoplen)) { expiretoplen)) {
/* we want to return rrset, but it may be /* we want to return rrset, but it may be
* gone from cache, if so, just loop like * gone from cache, if so, just loop like

View file

@ -234,6 +234,81 @@ setup_domain_limits(struct infra_cache* infra, struct config_file* cfg)
return 1; return 1;
} }
/** find or create element in wait limit netblock tree */
static struct wait_limit_netblock_info*
wait_limit_netblock_findcreate(struct infra_cache* infra, char* str,
int cookie)
{
rbtree_type* tree;
struct sockaddr_storage addr;
int net;
socklen_t addrlen;
struct wait_limit_netblock_info* d;
if(!netblockstrtoaddr(str, 0, &addr, &addrlen, &net)) {
log_err("cannot parse wait limit netblock '%s'", str);
return 0;
}
/* can we find it? */
if(cookie)
tree = &infra->wait_limits_cookie_netblock;
else
tree = &infra->wait_limits_netblock;
d = (struct wait_limit_netblock_info*)addr_tree_find(tree, &addr,
addrlen, net);
if(d)
return d;
/* create it */
d = (struct wait_limit_netblock_info*)calloc(1, sizeof(*d));
if(!d)
return NULL;
d->limit = -1;
if(!addr_tree_insert(tree, &d->node, &addr, addrlen, net)) {
log_err("duplicate element in domainlimit tree");
free(d);
return NULL;
}
return d;
}
/** insert wait limit information into lookup tree */
static int
infra_wait_limit_netblock_insert(struct infra_cache* infra,
struct config_file* cfg)
{
struct config_str2list* p;
struct wait_limit_netblock_info* d;
for(p = cfg->wait_limit_netblock; p; p = p->next) {
d = wait_limit_netblock_findcreate(infra, p->str, 0);
if(!d)
return 0;
d->limit = atoi(p->str2);
}
for(p = cfg->wait_limit_cookie_netblock; p; p = p->next) {
d = wait_limit_netblock_findcreate(infra, p->str, 1);
if(!d)
return 0;
d->limit = atoi(p->str2);
}
return 1;
}
/** setup wait limits tree (0 on failure) */
static int
setup_wait_limits(struct infra_cache* infra, struct config_file* cfg)
{
addr_tree_init(&infra->wait_limits_netblock);
addr_tree_init(&infra->wait_limits_cookie_netblock);
if(!infra_wait_limit_netblock_insert(infra, cfg))
return 0;
addr_tree_init_parents(&infra->wait_limits_netblock);
addr_tree_init_parents(&infra->wait_limits_cookie_netblock);
return 1;
}
struct infra_cache* struct infra_cache*
infra_create(struct config_file* cfg) infra_create(struct config_file* cfg)
{ {
@ -267,6 +342,10 @@ infra_create(struct config_file* cfg)
infra_delete(infra); infra_delete(infra);
return NULL; return NULL;
} }
if(!setup_wait_limits(infra, cfg)) {
infra_delete(infra);
return NULL;
}
infra_ip_ratelimit = cfg->ip_ratelimit; infra_ip_ratelimit = cfg->ip_ratelimit;
infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs, infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs,
INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc, INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc,
@ -287,6 +366,12 @@ static void domain_limit_free(rbnode_type* n, void* ATTR_UNUSED(arg))
} }
} }
/** delete wait_limit_netblock_info entries */
static void wait_limit_netblock_del(rbnode_type* n, void* ATTR_UNUSED(arg))
{
free(n);
}
void void
infra_delete(struct infra_cache* infra) infra_delete(struct infra_cache* infra)
{ {
@ -296,6 +381,10 @@ infra_delete(struct infra_cache* infra)
slabhash_delete(infra->domain_rates); slabhash_delete(infra->domain_rates);
traverse_postorder(&infra->domain_limits, domain_limit_free, NULL); traverse_postorder(&infra->domain_limits, domain_limit_free, NULL);
slabhash_delete(infra->client_ip_rates); slabhash_delete(infra->client_ip_rates);
traverse_postorder(&infra->wait_limits_netblock,
wait_limit_netblock_del, NULL);
traverse_postorder(&infra->wait_limits_cookie_netblock,
wait_limit_netblock_del, NULL);
free(infra); free(infra);
} }
@ -880,7 +969,8 @@ static void infra_create_ratedata(struct infra_cache* infra,
/** create rate data item for ip address */ /** create rate data item for ip address */
static void infra_ip_create_ratedata(struct infra_cache* infra, static void infra_ip_create_ratedata(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow) struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
int mesh_wait)
{ {
hashvalue_type h = hash_addr(addr, addrlen, 0); hashvalue_type h = hash_addr(addr, addrlen, 0);
struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k)); struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k));
@ -898,6 +988,7 @@ static void infra_ip_create_ratedata(struct infra_cache* infra,
k->entry.data = d; k->entry.data = d;
d->qps[0] = 1; d->qps[0] = 1;
d->timestamp[0] = timenow; d->timestamp[0] = timenow;
d->mesh_wait = mesh_wait;
slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL); slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL);
} }
@ -1121,6 +1212,81 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
} }
/* create */ /* create */
infra_ip_create_ratedata(infra, addr, addrlen, timenow); infra_ip_create_ratedata(infra, addr, addrlen, timenow, 0);
return 1; return 1;
} }
int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep,
int cookie_valid, struct config_file* cfg)
{
struct lruhash_entry* entry;
if(cfg->wait_limit == 0)
return 1;
entry = infra_find_ip_ratedata(infra, &rep->client_addr,
rep->client_addrlen, 0);
if(entry) {
rbtree_type* tree;
struct wait_limit_netblock_info* w;
struct rate_data* d = (struct rate_data*)entry->data;
int mesh_wait = d->mesh_wait;
lock_rw_unlock(&entry->lock);
/* have the wait amount, check how much is allowed */
if(cookie_valid)
tree = &infra->wait_limits_cookie_netblock;
else tree = &infra->wait_limits_netblock;
w = (struct wait_limit_netblock_info*)addr_tree_lookup(tree,
&rep->client_addr, rep->client_addrlen);
if(w) {
if(w->limit != -1 && mesh_wait > w->limit)
return 0;
} else {
/* if there is no IP netblock specific information,
* use the configured value. */
if(mesh_wait > (cookie_valid?cfg->wait_limit_cookie:
cfg->wait_limit))
return 0;
}
}
return 1;
}
void infra_wait_limit_inc(struct infra_cache* infra, struct comm_reply* rep,
time_t timenow, struct config_file* cfg)
{
struct lruhash_entry* entry;
if(cfg->wait_limit == 0)
return;
/* Find it */
entry = infra_find_ip_ratedata(infra, &rep->client_addr,
rep->client_addrlen, 1);
if(entry) {
struct rate_data* d = (struct rate_data*)entry->data;
d->mesh_wait++;
lock_rw_unlock(&entry->lock);
return;
}
/* Create it */
infra_ip_create_ratedata(infra, &rep->client_addr,
rep->client_addrlen, timenow, 1);
}
void infra_wait_limit_dec(struct infra_cache* infra, struct comm_reply* rep,
struct config_file* cfg)
{
struct lruhash_entry* entry;
if(cfg->wait_limit == 0)
return;
entry = infra_find_ip_ratedata(infra, &rep->client_addr,
rep->client_addrlen, 1);
if(entry) {
struct rate_data* d = (struct rate_data*)entry->data;
if(d->mesh_wait > 0)
d->mesh_wait--;
lock_rw_unlock(&entry->lock);
}
}

View file

@ -122,6 +122,10 @@ struct infra_cache {
rbtree_type domain_limits; rbtree_type domain_limits;
/** hash table with query rates per client ip: ip_rate_key, ip_rate_data */ /** hash table with query rates per client ip: ip_rate_key, ip_rate_data */
struct slabhash* client_ip_rates; struct slabhash* client_ip_rates;
/** tree of addr_tree_node, with wait_limit_netblock_info information */
rbtree_type wait_limits_netblock;
/** tree of addr_tree_node, with wait_limit_netblock_info information */
rbtree_type wait_limits_cookie_netblock;
}; };
/** ratelimit, unless overridden by domain_limits, 0 is off */ /** ratelimit, unless overridden by domain_limits, 0 is off */
@ -184,10 +188,22 @@ struct rate_data {
/** what the timestamp is of the qps array members, counter is /** what the timestamp is of the qps array members, counter is
* valid for that timestamp. Usually now and now-1. */ * valid for that timestamp. Usually now and now-1. */
time_t timestamp[RATE_WINDOW]; time_t timestamp[RATE_WINDOW];
/** the number of queries waiting in the mesh */
int mesh_wait;
}; };
#define ip_rate_data rate_data #define ip_rate_data rate_data
/**
* Data to store the configuration per netblock for the wait limit
*/
struct wait_limit_netblock_info {
/** The addr tree node, this must be first. */
struct addr_tree_node node;
/** the limit on the amount */
int limit;
};
/** infra host cache default hash lookup size */ /** infra host cache default hash lookup size */
#define INFRA_HOST_STARTSIZE 32 #define INFRA_HOST_STARTSIZE 32
/** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */ /** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */
@ -474,4 +490,16 @@ void ip_rate_delkeyfunc(void* d, void* arg);
/* delete data */ /* delete data */
#define ip_rate_deldatafunc rate_deldatafunc #define ip_rate_deldatafunc rate_deldatafunc
/** See if the IP address can have another reply in the wait limit */
int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep,
int cookie_valid, struct config_file* cfg);
/** Increment number of waiting replies for IP */
void infra_wait_limit_inc(struct infra_cache* infra, struct comm_reply* rep,
time_t timenow, struct config_file* cfg);
/** Decrement number of waiting replies for IP */
void infra_wait_limit_dec(struct infra_cache* infra, struct comm_reply* rep,
struct config_file* cfg);
#endif /* SERVICES_CACHE_INFRA_H */ #endif /* SERVICES_CACHE_INFRA_H */

View file

@ -46,6 +46,7 @@
#include "util/data/packed_rrset.h" #include "util/data/packed_rrset.h"
#include "util/data/msgreply.h" #include "util/data/msgreply.h"
#include "util/data/msgparse.h" #include "util/data/msgparse.h"
#include "util/data/dname.h"
#include "util/regional.h" #include "util/regional.h"
#include "util/alloc.h" #include "util/alloc.h"
#include "util/net_help.h" #include "util/net_help.h"
@ -127,6 +128,9 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
{ {
struct packed_rrset_data* newd = (struct packed_rrset_data*)nd; struct packed_rrset_data* newd = (struct packed_rrset_data*)nd;
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd; struct packed_rrset_data* cached = (struct packed_rrset_data*)cd;
/* o if new data is expired, current data is better */
if( newd->ttl < timenow && cached->ttl >= timenow)
return 0;
/* o store if rrset has been validated /* o store if rrset has been validated
* everything better than bogus data * everything better than bogus data
* secure is preferred */ * secure is preferred */
@ -440,6 +444,89 @@ rrset_check_sec_status(struct rrset_cache* r,
lock_rw_unlock(&e->lock); lock_rw_unlock(&e->lock);
} }
void
rrset_cache_remove_above(struct rrset_cache* r, uint8_t** qname, size_t*
qnamelen, uint16_t searchtype, uint16_t qclass, time_t now, uint8_t*
qnametop, size_t qnametoplen)
{
struct ub_packed_rrset_key *rrset;
uint8_t lablen;
while(*qnamelen > 0) {
/* look one label higher */
lablen = **qname;
*qname += lablen + 1;
*qnamelen -= lablen + 1;
if(*qnamelen <= 0)
return;
/* stop at qnametop */
if(qnametop && *qnamelen == qnametoplen &&
query_dname_compare(*qname, qnametop)==0)
return;
if(verbosity >= VERB_ALGO) {
/* looks up with a time of 0, to see expired entries */
if((rrset = rrset_cache_lookup(r, *qname,
*qnamelen, searchtype, qclass, 0, 0, 0))) {
struct packed_rrset_data* data =
(struct packed_rrset_data*)rrset->entry.data;
int expired = (now > data->ttl);
lock_rw_unlock(&rrset->entry.lock);
if(expired)
log_nametypeclass(verbosity, "this "
"(grand)parent rrset will be "
"removed (expired)",
*qname, searchtype, qclass);
else log_nametypeclass(verbosity, "this "
"(grand)parent rrset will be "
"removed",
*qname, searchtype, qclass);
}
}
rrset_cache_remove(r, *qname, *qnamelen, searchtype, qclass, 0);
}
}
int
rrset_cache_expired_above(struct rrset_cache* r, uint8_t** qname, size_t*
qnamelen, uint16_t searchtype, uint16_t qclass, time_t now, uint8_t*
qnametop, size_t qnametoplen)
{
struct ub_packed_rrset_key *rrset;
uint8_t lablen;
while(*qnamelen > 0) {
/* look one label higher */
lablen = **qname;
*qname += lablen + 1;
*qnamelen -= lablen + 1;
if(*qnamelen <= 0)
break;
/* looks up with a time of 0, to see expired entries */
if((rrset = rrset_cache_lookup(r, *qname,
*qnamelen, searchtype, qclass, 0, 0, 0))) {
struct packed_rrset_data* data =
(struct packed_rrset_data*)rrset->entry.data;
if(now > data->ttl) {
/* it is expired, this is not wanted */
lock_rw_unlock(&rrset->entry.lock);
log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass);
return 1;
}
/* it is not expired, continue looking */
lock_rw_unlock(&rrset->entry.lock);
}
/* do not look above the qnametop. */
if(qnametop && *qnamelen == qnametoplen &&
query_dname_compare(*qname, qnametop)==0)
break;
}
return 0;
}
void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen, void rrset_cache_remove(struct rrset_cache* r, uint8_t* nm, size_t nmlen,
uint16_t type, uint16_t dclass, uint32_t flags) uint16_t type, uint16_t dclass, uint32_t flags)
{ {

View file

@ -231,6 +231,37 @@ void rrset_update_sec_status(struct rrset_cache* r,
void rrset_check_sec_status(struct rrset_cache* r, void rrset_check_sec_status(struct rrset_cache* r,
struct ub_packed_rrset_key* rrset, time_t now); struct ub_packed_rrset_key* rrset, time_t now);
/**
* Removes rrsets above the qname, returns upper qname.
* @param r: the rrset cache.
* @param qname: the start qname, also used as the output.
* @param qnamelen: length of qname, updated when it returns.
* @param searchtype: qtype to search for.
* @param qclass: qclass to search for.
* @param now: current time.
* @param qnametop: the top qname to stop removal (it is not removed).
* @param qnametoplen: length of qnametop.
*/
void rrset_cache_remove_above(struct rrset_cache* r, uint8_t** qname,
size_t* qnamelen, uint16_t searchtype, uint16_t qclass, time_t now,
uint8_t* qnametop, size_t qnametoplen);
/**
* Sees if an rrset is expired above the qname, returns upper qname.
* @param r: the rrset cache.
* @param qname: the start qname, also used as the output.
* @param qnamelen: length of qname, updated when it returns.
* @param searchtype: qtype to search for.
* @param qclass: qclass to search for.
* @param now: current time.
* @param qnametop: the top qname, don't look farther than that.
* @param qnametoplen: length of qnametop.
* @return true if there is an expired rrset above, false otherwise.
*/
int rrset_cache_expired_above(struct rrset_cache* r, uint8_t** qname,
size_t* qnamelen, uint16_t searchtype, uint16_t qclass, time_t now,
uint8_t* qnametop, size_t qnametoplen);
/** /**
* Remove an rrset from the cache, by name and type and flags * Remove an rrset from the cache, by name and type and flags
* @param r: rrset cache * @param r: rrset cache

View file

@ -140,9 +140,11 @@ void
verbose_print_unbound_socket(struct unbound_socket* ub_sock) verbose_print_unbound_socket(struct unbound_socket* ub_sock)
{ {
if(verbosity >= VERB_ALGO) { if(verbosity >= VERB_ALGO) {
char buf[256];
log_info("listing of unbound_socket structure:"); log_info("listing of unbound_socket structure:");
verbose_print_addr(ub_sock->addr); addr_to_str((void*)ub_sock->addr, ub_sock->addrlen, buf,
log_info("s is: %d, fam is: %s, acl: %s", ub_sock->s, sizeof(buf));
log_info("%s s is: %d, fam is: %s, acl: %s", buf, ub_sock->s,
ub_sock->fam == AF_INET?"AF_INET":"AF_INET6", ub_sock->fam == AF_INET?"AF_INET":"AF_INET6",
ub_sock->acl?"yes":"no"); ub_sock->acl?"yes":"no");
} }
@ -610,7 +612,9 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
# elif defined(IP_DONTFRAG) && !defined(__APPLE__) # elif defined(IP_DONTFRAG) && !defined(__APPLE__)
/* the IP_DONTFRAG option if defined in the 11.0 OSX headers, /* the IP_DONTFRAG option if defined in the 11.0 OSX headers,
* but does not work on that version, so we exclude it */ * but does not work on that version, so we exclude it */
int off = 0; /* a nonzero value disables fragmentation, according to
* docs.oracle.com for ip(4). */
int off = 1;
if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG, if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
&off, (socklen_t)sizeof(off)) < 0) { &off, (socklen_t)sizeof(off)) < 0) {
log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s", log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s",
@ -1047,7 +1051,22 @@ make_sock(int stype, const char* ifname, const char* port,
} }
} }
ub_sock->addr = res; if(!res->ai_addr) {
log_err("getaddrinfo returned no address");
freeaddrinfo(res);
sock_close(s);
return -1;
}
ub_sock->addr = memdup(res->ai_addr, res->ai_addrlen);
ub_sock->addrlen = res->ai_addrlen;
if(!ub_sock->addr) {
log_err("out of memory: allocate listening address");
freeaddrinfo(res);
sock_close(s);
return -1;
}
freeaddrinfo(res);
ub_sock->s = s; ub_sock->s = s;
ub_sock->fam = hints->ai_family; ub_sock->fam = hints->ai_family;
ub_sock->acl = NULL; ub_sock->acl = NULL;
@ -1277,8 +1296,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
&noip6, rcv, snd, reuseport, transparent, &noip6, rcv, snd, reuseport, transparent,
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) { tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) {
if(ub_sock->addr) free(ub_sock->addr);
freeaddrinfo(ub_sock->addr);
free(ub_sock); free(ub_sock);
if(noip6) { if(noip6) {
log_warn("IPv6 protocol not available"); log_warn("IPv6 protocol not available");
@ -1289,8 +1307,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
/* getting source addr packet info is highly non-portable */ /* getting source addr packet info is highly non-portable */
if(!set_recvpktinfo(s, hints->ai_family)) { if(!set_recvpktinfo(s, hints->ai_family)) {
sock_close(s); sock_close(s);
if(ub_sock->addr) free(ub_sock->addr);
freeaddrinfo(ub_sock->addr);
free(ub_sock); free(ub_sock);
return 0; return 0;
} }
@ -1301,8 +1318,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
?listen_type_udpancil_dnscrypt:listen_type_udpancil, ?listen_type_udpancil_dnscrypt:listen_type_udpancil,
is_pp2, ub_sock)) { is_pp2, ub_sock)) {
sock_close(s); sock_close(s);
if(ub_sock->addr) free(ub_sock->addr);
freeaddrinfo(ub_sock->addr);
free(ub_sock); free(ub_sock);
return 0; return 0;
} }
@ -1314,8 +1330,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
&noip6, rcv, snd, reuseport, transparent, &noip6, rcv, snd, reuseport, transparent,
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) { tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) {
if(ub_sock->addr) free(ub_sock->addr);
freeaddrinfo(ub_sock->addr);
free(ub_sock); free(ub_sock);
if(noip6) { if(noip6) {
log_warn("IPv6 protocol not available"); log_warn("IPv6 protocol not available");
@ -1332,8 +1347,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
listen_type_udpancil:listen_type_udp), listen_type_udpancil:listen_type_udp),
is_pp2, ub_sock)) { is_pp2, ub_sock)) {
sock_close(s); sock_close(s);
if(ub_sock->addr) free(ub_sock->addr);
freeaddrinfo(ub_sock->addr);
free(ub_sock); free(ub_sock);
return 0; return 0;
} }
@ -1356,8 +1370,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1, if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1,
&noip6, 0, 0, reuseport, transparent, tcp_mss, nodelay, &noip6, 0, 0, reuseport, transparent, tcp_mss, nodelay,
freebind, use_systemd, dscp, ub_sock)) == -1) { freebind, use_systemd, dscp, ub_sock)) == -1) {
if(ub_sock->addr) free(ub_sock->addr);
freeaddrinfo(ub_sock->addr);
free(ub_sock); free(ub_sock);
if(noip6) { if(noip6) {
/*log_warn("IPv6 protocol not available");*/ /*log_warn("IPv6 protocol not available");*/
@ -1369,8 +1382,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
verbose(VERB_ALGO, "setup TCP for SSL service"); verbose(VERB_ALGO, "setup TCP for SSL service");
if(!port_insert(list, s, port_type, is_pp2, ub_sock)) { if(!port_insert(list, s, port_type, is_pp2, ub_sock)) {
sock_close(s); sock_close(s);
if(ub_sock->addr) free(ub_sock->addr);
freeaddrinfo(ub_sock->addr);
free(ub_sock); free(ub_sock);
return 0; return 0;
} }
@ -1952,8 +1964,7 @@ void listening_ports_free(struct listen_port* list)
} }
/* rc_ports don't have ub_socket */ /* rc_ports don't have ub_socket */
if(list->socket) { if(list->socket) {
if(list->socket->addr) free(list->socket->addr);
freeaddrinfo(list->socket->addr);
free(list->socket); free(list->socket);
} }
free(list); free(list);

View file

@ -107,11 +107,13 @@ enum listen_type {
* socket properties (just like NSD nsd_socket structure definition) * socket properties (just like NSD nsd_socket structure definition)
*/ */
struct unbound_socket { struct unbound_socket {
/** socket-address structure */ /** the address of the socket */
struct addrinfo* addr; struct sockaddr* addr;
/** length of the address */
socklen_t addrlen;
/** socket descriptor returned by socket() syscall */ /** socket descriptor returned by socket() syscall */
int s; int s;
/** address family (AF_INET/IF_INET6) */ /** address family (AF_INET/AF_INET6) */
int fam; int fam;
/** ACL on the socket (listening interface) */ /** ACL on the socket (listening interface) */
struct acl_addr* acl; struct acl_addr* acl;

View file

@ -330,14 +330,16 @@ get_rr_nameclass(const char* str, uint8_t** nm, uint16_t* dclass,
static struct local_rrset* static struct local_rrset*
local_data_find_type(struct local_data* data, uint16_t type, int alias_ok) local_data_find_type(struct local_data* data, uint16_t type, int alias_ok)
{ {
struct local_rrset* p; struct local_rrset* p, *cname = NULL;
type = htons(type); type = htons(type);
for(p = data->rrsets; p; p = p->next) { for(p = data->rrsets; p; p = p->next) {
if(p->rrset->rk.type == type) if(p->rrset->rk.type == type)
return p; return p;
if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
return p; cname = p;
} }
if(alias_ok)
return cname;
return NULL; return NULL;
} }

View file

@ -47,6 +47,7 @@
#include "services/outbound_list.h" #include "services/outbound_list.h"
#include "services/cache/dns.h" #include "services/cache/dns.h"
#include "services/cache/rrset.h" #include "services/cache/rrset.h"
#include "services/cache/infra.h"
#include "util/log.h" #include "util/log.h"
#include "util/net_help.h" #include "util/net_help.h"
#include "util/module.h" #include "util/module.h"
@ -385,7 +386,7 @@ mesh_serve_expired_init(struct mesh_state* mstate, int timeout)
&mesh_serve_expired_lookup; &mesh_serve_expired_lookup;
/* In case this timer already popped, start it again */ /* In case this timer already popped, start it again */
if(!mstate->s.serve_expired_data->timer) { if(!mstate->s.serve_expired_data->timer && timeout != -1) {
mstate->s.serve_expired_data->timer = comm_timer_create( mstate->s.serve_expired_data->timer = comm_timer_create(
mstate->s.env->worker_base, mesh_serve_expired_callback, mstate); mstate->s.env->worker_base, mesh_serve_expired_callback, mstate);
if(!mstate->s.serve_expired_data->timer) if(!mstate->s.serve_expired_data->timer)
@ -415,6 +416,14 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
if(rep->c->tcp_req_info) { if(rep->c->tcp_req_info) {
r_buffer = rep->c->tcp_req_info->spool_buffer; r_buffer = rep->c->tcp_req_info->spool_buffer;
} }
if(!infra_wait_limit_allowed(mesh->env->infra_cache, rep,
edns->cookie_valid, mesh->env->cfg)) {
verbose(VERB_ALGO, "Too many queries waiting from the IP. "
"dropping incoming query.");
comm_point_drop_reply(rep);
mesh->stats_dropped++;
return;
}
if(!unique) if(!unique)
s = mesh_area_find(mesh, cinfo, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); s = mesh_area_find(mesh, cinfo, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
/* does this create a new reply state? */ /* does this create a new reply state? */
@ -511,6 +520,19 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
log_err("mesh_new_client: out of memory initializing serve expired"); log_err("mesh_new_client: out of memory initializing serve expired");
goto servfail_mem; goto servfail_mem;
} }
#ifdef USE_CACHEDB
if(!timeout && mesh->env->cfg->serve_expired &&
!mesh->env->cfg->serve_expired_client_timeout &&
(mesh->env->cachedb_enabled &&
mesh->env->cfg->cachedb_check_when_serve_expired)) {
if(!mesh_serve_expired_init(s, -1)) {
log_err("mesh_new_client: out of memory initializing serve expired");
goto servfail_mem;
}
}
#endif
infra_wait_limit_inc(mesh->env->infra_cache, rep, *mesh->env->now,
mesh->env->cfg);
/* update statistics */ /* update statistics */
if(was_detached) { if(was_detached) {
log_assert(mesh->num_detached_states > 0); log_assert(mesh->num_detached_states > 0);
@ -616,6 +638,18 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
mesh_state_delete(&s->s); mesh_state_delete(&s->s);
return 0; return 0;
} }
#ifdef USE_CACHEDB
if(!timeout && mesh->env->cfg->serve_expired &&
!mesh->env->cfg->serve_expired_client_timeout &&
(mesh->env->cachedb_enabled &&
mesh->env->cfg->cachedb_check_when_serve_expired)) {
if(!mesh_serve_expired_init(s, -1)) {
if(added)
mesh_state_delete(&s->s);
return 0;
}
}
#endif
/* update statistics */ /* update statistics */
if(was_detached) { if(was_detached) {
log_assert(mesh->num_detached_states > 0); log_assert(mesh->num_detached_states > 0);
@ -930,6 +964,8 @@ mesh_state_cleanup(struct mesh_state* mstate)
* takes no time and also it does not do the mesh accounting */ * takes no time and also it does not do the mesh accounting */
mstate->reply_list = NULL; mstate->reply_list = NULL;
for(; rep; rep=rep->next) { for(; rep; rep=rep->next) {
infra_wait_limit_dec(mesh->env->infra_cache,
&rep->query_reply, mesh->env->cfg);
comm_point_drop_reply(&rep->query_reply); comm_point_drop_reply(&rep->query_reply);
log_assert(mesh->num_reply_addrs > 0); log_assert(mesh->num_reply_addrs > 0);
mesh->num_reply_addrs--; mesh->num_reply_addrs--;
@ -1179,7 +1215,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
rcode = LDNS_RCODE_SERVFAIL; rcode = LDNS_RCODE_SERVFAIL;
if(!rcode && rep && (rep->security == sec_status_bogus || if(!rcode && rep && (rep->security == sec_status_bogus ||
rep->security == sec_status_secure_sentinel_fail)) { rep->security == sec_status_secure_sentinel_fail)) {
if(!(reason = errinf_to_str_bogus(&m->s))) if(!(reason = errinf_to_str_bogus(&m->s, NULL)))
rcode = LDNS_RCODE_SERVFAIL; rcode = LDNS_RCODE_SERVFAIL;
} }
/* send the reply */ /* send the reply */
@ -1413,6 +1449,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
comm_point_send_reply(&r->query_reply); comm_point_send_reply(&r->query_reply);
m->reply_list = rlist; m->reply_list = rlist;
} }
infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply,
m->s.env->cfg);
/* account */ /* account */
log_assert(m->s.env->mesh->num_reply_addrs > 0); log_assert(m->s.env->mesh->num_reply_addrs > 0);
m->s.env->mesh->num_reply_addrs--; m->s.env->mesh->num_reply_addrs--;
@ -1436,7 +1474,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
log_reply_info(NO_VERBOSE, &m->s.qinfo, log_reply_info(NO_VERBOSE, &m->s.qinfo,
&r->query_reply.client_addr, &r->query_reply.client_addr,
r->query_reply.client_addrlen, duration, 0, r_buffer, r->query_reply.client_addrlen, duration, 0, r_buffer,
(m->s.env->cfg->log_destaddr?(void*)r->query_reply.c->socket->addr->ai_addr:NULL), (m->s.env->cfg->log_destaddr?(void*)r->query_reply.c->socket->addr:NULL),
r->query_reply.c->type); r->query_reply.c->type);
} }
} }
@ -1464,12 +1502,32 @@ void mesh_query_done(struct mesh_state* mstate)
&& mstate->s.env->cfg->log_servfail && mstate->s.env->cfg->log_servfail
&& !mstate->s.env->cfg->val_log_squelch) { && !mstate->s.env->cfg->val_log_squelch) {
char* err = errinf_to_str_servfail(&mstate->s); char* err = errinf_to_str_servfail(&mstate->s);
if(err) if(err) { log_err("%s", err); }
log_err("%s", err);
free(err);
} }
} }
for(r = mstate->reply_list; r; r = r->next) { for(r = mstate->reply_list; r; r = r->next) {
struct timeval old;
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
if(mstate->s.env->cfg->discard_timeout != 0 &&
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
mstate->s.env->cfg->discard_timeout) {
/* Drop the reply, it is too old */
/* briefly set the reply_list to NULL, so that the
* tcp req info cleanup routine that calls the mesh
* to deregister the meshstate for it is not done
* because the list is NULL and also accounting is not
* done there, but instead we do that here. */
struct mesh_reply* reply_list = mstate->reply_list;
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
mstate->reply_list = NULL;
comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list;
mstate->s.env->mesh->stats_dropped++;
continue;
}
i++; i++;
tv = r->start_time; tv = r->start_time;
@ -1493,6 +1551,8 @@ void mesh_query_done(struct mesh_state* mstate)
* because the list is NULL and also accounting is not * because the list is NULL and also accounting is not
* done there, but instead we do that here. */ * done there, but instead we do that here. */
struct mesh_reply* reply_list = mstate->reply_list; struct mesh_reply* reply_list = mstate->reply_list;
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
mstate->reply_list = NULL; mstate->reply_list = NULL;
comm_point_drop_reply(&r->query_reply); comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list; mstate->reply_list = reply_list;
@ -2025,6 +2085,8 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
/* delete it, but allocated in m region */ /* delete it, but allocated in m region */
log_assert(mesh->num_reply_addrs > 0); log_assert(mesh->num_reply_addrs > 0);
mesh->num_reply_addrs--; mesh->num_reply_addrs--;
infra_wait_limit_dec(mesh->env->infra_cache,
&n->query_reply, mesh->env->cfg);
/* prev = prev; */ /* prev = prev; */
n = n->next; n = n->next;
@ -2165,6 +2227,28 @@ mesh_serve_expired_callback(void* arg)
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep); log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
for(r = mstate->reply_list; r; r = r->next) { for(r = mstate->reply_list; r; r = r->next) {
struct timeval old;
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
if(mstate->s.env->cfg->discard_timeout != 0 &&
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
mstate->s.env->cfg->discard_timeout) {
/* Drop the reply, it is too old */
/* briefly set the reply_list to NULL, so that the
* tcp req info cleanup routine that calls the mesh
* to deregister the meshstate for it is not done
* because the list is NULL and also accounting is not
* done there, but instead we do that here. */
struct mesh_reply* reply_list = mstate->reply_list;
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
mstate->reply_list = NULL;
comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list;
mstate->s.env->mesh->stats_dropped++;
continue;
}
i++; i++;
tv = r->start_time; tv = r->start_time;
@ -2192,6 +2276,8 @@ mesh_serve_expired_callback(void* arg)
r, r_buffer, prev, prev_buffer); r, r_buffer, prev, prev_buffer);
if(r->query_reply.c->tcp_req_info) if(r->query_reply.c->tcp_req_info)
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
prev = r; prev = r;
prev_buffer = r_buffer; prev_buffer = r_buffer;
} }
@ -2238,6 +2324,14 @@ mesh_serve_expired_callback(void* arg)
} }
} }
void
mesh_respond_serve_expired(struct mesh_state* mstate)
{
if(!mstate->s.serve_expired_data)
mesh_serve_expired_init(mstate, -1);
mesh_serve_expired_callback(mstate);
}
int mesh_jostle_exceeded(struct mesh_area* mesh) int mesh_jostle_exceeded(struct mesh_area* mesh)
{ {
if(mesh->all.count < mesh->max_reply_states) if(mesh->all.count < mesh->max_reply_states)

View file

@ -690,4 +690,10 @@ mesh_serve_expired_lookup(struct module_qstate* qstate,
*/ */
int mesh_jostle_exceeded(struct mesh_area* mesh); int mesh_jostle_exceeded(struct mesh_area* mesh);
/**
* Give the serve expired responses.
* @param mstate: mesh state for query that has serve_expired_data.
*/
void mesh_respond_serve_expired(struct mesh_state* mstate);
#endif /* SERVICES_MESH_H */ #endif /* SERVICES_MESH_H */

View file

@ -478,6 +478,67 @@ new_cname_override(struct regional* region, uint8_t* ct, size_t ctlen)
return rrset; return rrset;
} }
/** delete the cname override */
static void
delete_cname_override(struct rpz* r)
{
if(r->cname_override) {
/* The cname override is what is allocated in the region. */
regional_free_all(r->region);
r->cname_override = NULL;
}
}
/** Apply rpz config elements to the rpz structure, false on failure. */
static int
rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p)
{
if(p->rpz_taglist && p->rpz_taglistlen) {
r->taglistlen = p->rpz_taglistlen;
r->taglist = memdup(p->rpz_taglist, r->taglistlen);
if(!r->taglist) {
log_err("malloc failure on RPZ taglist alloc");
return 0;
}
}
if(p->rpz_action_override) {
r->action_override = rpz_config_to_action(p->rpz_action_override);
}
else
r->action_override = RPZ_NO_OVERRIDE_ACTION;
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
uint8_t nm[LDNS_MAX_DOMAINLEN+1];
size_t nmlen = sizeof(nm);
if(!p->rpz_cname) {
log_err("rpz: override with cname action found, but no "
"rpz-cname-override configured");
return 0;
}
if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) {
log_err("rpz: cannot parse cname override: %s",
p->rpz_cname);
return 0;
}
r->cname_override = new_cname_override(r->region, nm, nmlen);
if(!r->cname_override) {
return 0;
}
}
r->log = p->rpz_log;
r->signal_nxdomain_ra = p->rpz_signal_nxdomain_ra;
if(p->rpz_log_name) {
if(!(r->log_name = strdup(p->rpz_log_name))) {
log_err("malloc failure on RPZ log_name strdup");
return 0;
}
}
return 1;
}
struct rpz* struct rpz*
rpz_create(struct config_auth* p) rpz_create(struct config_auth* p)
{ {
@ -513,42 +574,8 @@ rpz_create(struct config_auth* p)
goto err; goto err;
} }
r->taglistlen = p->rpz_taglistlen; if(!rpz_apply_cfg_elements(r, p))
r->taglist = memdup(p->rpz_taglist, r->taglistlen); goto err;
if(p->rpz_action_override) {
r->action_override = rpz_config_to_action(p->rpz_action_override);
}
else
r->action_override = RPZ_NO_OVERRIDE_ACTION;
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
uint8_t nm[LDNS_MAX_DOMAINLEN+1];
size_t nmlen = sizeof(nm);
if(!p->rpz_cname) {
log_err("rpz: override with cname action found, but no "
"rpz-cname-override configured");
goto err;
}
if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) {
log_err("rpz: cannot parse cname override: %s",
p->rpz_cname);
goto err;
}
r->cname_override = new_cname_override(r->region, nm, nmlen);
if(!r->cname_override) {
goto err;
}
}
r->log = p->rpz_log;
r->signal_nxdomain_ra = p->rpz_signal_nxdomain_ra;
if(p->rpz_log_name) {
if(!(r->log_name = strdup(p->rpz_log_name))) {
log_err("malloc failure on RPZ log_name strdup");
goto err;
}
}
return r; return r;
err: err:
if(r) { if(r) {
@ -571,6 +598,32 @@ err:
return NULL; return NULL;
} }
int
rpz_config(struct rpz* r, struct config_auth* p)
{
/* If the zonefile changes, it is read later, after which
* rpz_clear and rpz_finish_config is called. */
/* free taglist, if any */
if(r->taglist) {
free(r->taglist);
r->taglist = NULL;
r->taglistlen = 0;
}
/* free logname, if any */
if(r->log_name) {
free(r->log_name);
r->log_name = NULL;
}
delete_cname_override(r);
if(!rpz_apply_cfg_elements(r, p))
return 0;
return 1;
}
/** /**
* Remove RPZ zone name from dname * Remove RPZ zone name from dname
* Copy dname to newdname, without the originlen number of trailing bytes * Copy dname to newdname, without the originlen number of trailing bytes
@ -1191,16 +1244,20 @@ rpz_find_zone(struct local_zones* zones, uint8_t* qname, size_t qname_len, uint1
/** Find entry for RR type in the list of rrsets for the clientip. */ /** Find entry for RR type in the list of rrsets for the clientip. */
static struct local_rrset* static struct local_rrset*
rpz_find_synthesized_rrset(uint16_t qtype, rpz_find_synthesized_rrset(uint16_t qtype,
struct clientip_synthesized_rr* data) struct clientip_synthesized_rr* data, int alias_ok)
{ {
struct local_rrset* cursor = data->data; struct local_rrset* cursor = data->data, *cname = NULL;
while( cursor != NULL) { while( cursor != NULL) {
struct packed_rrset_key* packed_rrset = &cursor->rrset->rk; struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
if(htons(qtype) == packed_rrset->type) { if(htons(qtype) == packed_rrset->type) {
return cursor; return cursor;
} }
if(ntohs(packed_rrset->type) == LDNS_RR_TYPE_CNAME && alias_ok)
cname = cursor;
cursor = cursor->next; cursor = cursor->next;
} }
if(alias_ok)
return cname;
return NULL; return NULL;
} }
@ -1386,7 +1443,7 @@ static int rpz_remove_clientip_rr(struct clientip_synthesized_rr* node,
struct local_rrset* rrset; struct local_rrset* rrset;
struct packed_rrset_data* d; struct packed_rrset_data* d;
size_t index; size_t index;
rrset = rpz_find_synthesized_rrset(rr_type, node); rrset = rpz_find_synthesized_rrset(rr_type, node, 0);
if(rrset == NULL) if(rrset == NULL)
return 0; /* type not found, ignore */ return 0; /* type not found, ignore */
d = (struct packed_rrset_data*)rrset->rrset->entry.data; d = (struct packed_rrset_data*)rrset->rrset->entry.data;
@ -1789,7 +1846,7 @@ rpz_apply_clientip_localdata_action(struct clientip_synthesized_rr* raddr,
} }
/* check query type / rr type */ /* check query type / rr type */
rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr); rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr, 1);
if(rrset == NULL) { if(rrset == NULL) {
verbose(VERB_ALGO, "rpz: unable to find local-data for query"); verbose(VERB_ALGO, "rpz: unable to find local-data for query");
rrset_count = 0; rrset_count = 0;
@ -1823,6 +1880,28 @@ nodata:
rrset_count, rcode, rsoa); rrset_count, rcode, rsoa);
} }
/** Apply the cname override action, during worker request callback.
* false on failure. */
static int
rpz_apply_cname_override_action(struct rpz* r,
struct query_info* qinfo, struct regional* temp)
{
if(!r)
return 0;
qinfo->local_alias = regional_alloc_zero(temp,
sizeof(struct local_rrset));
if(qinfo->local_alias == NULL)
return 0; /* out of memory */
qinfo->local_alias->rrset = respip_copy_rrset(r->cname_override, temp);
if(qinfo->local_alias->rrset == NULL) {
qinfo->local_alias = NULL;
return 0; /* out of memory */
}
qinfo->local_alias->rrset->rk.dname = qinfo->qname;
qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
return 1;
}
/** add additional section SOA record to the reply. /** add additional section SOA record to the reply.
* Since this gets fed into the normal iterator answer creation, it * Since this gets fed into the normal iterator answer creation, it
* gets minimal-responses applied to it, that can remove the additional SOA * gets minimal-responses applied to it, that can remove the additional SOA
@ -1933,6 +2012,7 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs
msg = rpz_dns_msg_new(ms->region); msg = rpz_dns_msg_new(ms->region);
if(msg == NULL) { return NULL; } if(msg == NULL) { return NULL; }
msg->qinfo = *qi;
new_reply_info = construct_reply_info_base(ms->region, new_reply_info = construct_reply_info_base(ms->region,
LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA, LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA,
1, /* qd */ 1, /* qd */
@ -1975,40 +2055,42 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs
static inline struct dns_msg* static inline struct dns_msg*
rpz_synthesize_nsip_localdata(struct rpz* r, struct module_qstate* ms, rpz_synthesize_nsip_localdata(struct rpz* r, struct module_qstate* ms,
struct clientip_synthesized_rr* data, struct auth_zone* az) struct query_info* qi, struct clientip_synthesized_rr* data,
struct auth_zone* az)
{ {
struct query_info* qi = &ms->qinfo;
struct local_rrset* rrset; struct local_rrset* rrset;
rrset = rpz_find_synthesized_rrset(qi->qtype, data); rrset = rpz_find_synthesized_rrset(qi->qtype, data, 1);
if(rrset == NULL) { if(rrset == NULL) {
verbose(VERB_ALGO, "rpz: nsip: no matching local data found"); verbose(VERB_ALGO, "rpz: nsip: no matching local data found");
return NULL; return NULL;
} }
return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset, az); return rpz_synthesize_localdata_from_rrset(r, ms, qi, rrset, az);
} }
/* copy'n'paste from localzone.c */ /* copy'n'paste from localzone.c */
static struct local_rrset* static struct local_rrset*
local_data_find_type(struct local_data* data, uint16_t type, int alias_ok) local_data_find_type(struct local_data* data, uint16_t type, int alias_ok)
{ {
struct local_rrset* p; struct local_rrset* p, *cname = NULL;
type = htons(type); type = htons(type);
for(p = data->rrsets; p; p = p->next) { for(p = data->rrsets; p; p = p->next) {
if(p->rrset->rk.type == type) if(p->rrset->rk.type == type)
return p; return p;
if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
return p; cname = p;
} }
if(alias_ok)
return cname;
return NULL; return NULL;
} }
/* based on localzone.c:local_data_answer() */ /* based on localzone.c:local_data_answer() */
static inline struct dns_msg* static inline struct dns_msg*
rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms, rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
struct local_zone* z, struct matched_delegation_point const* match, struct query_info* qi, struct local_zone* z,
struct auth_zone* az) struct matched_delegation_point const* match, struct auth_zone* az)
{ {
struct local_data key; struct local_data key;
struct local_data* ld; struct local_data* ld;
@ -2029,13 +2111,13 @@ rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
return NULL; return NULL;
} }
rrset = local_data_find_type(ld, ms->qinfo.qtype, 1); rrset = local_data_find_type(ld, qi->qtype, 1);
if(rrset == NULL) { if(rrset == NULL) {
verbose(VERB_ALGO, "rpz: nsdname: no matching local data found"); verbose(VERB_ALGO, "rpz: nsdname: no matching local data found");
return NULL; return NULL;
} }
return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset, az); return rpz_synthesize_localdata_from_rrset(r, ms, qi, rrset, az);
} }
/* like local_data_answer for qname triggers after a cname */ /* like local_data_answer for qname triggers after a cname */
@ -2052,17 +2134,70 @@ rpz_synthesize_qname_localdata_msg(struct rpz* r, struct module_qstate* ms,
key.namelabs = dname_count_labels(qinfo->qname); key.namelabs = dname_count_labels(qinfo->qname);
ld = (struct local_data*)rbtree_search(&z->data, &key.node); ld = (struct local_data*)rbtree_search(&z->data, &key.node);
if(ld == NULL) { if(ld == NULL) {
verbose(VERB_ALGO, "rpz: qname after cname: name not found"); verbose(VERB_ALGO, "rpz: qname: name not found");
return NULL; return NULL;
} }
rrset = local_data_find_type(ld, qinfo->qtype, 1); rrset = local_data_find_type(ld, qinfo->qtype, 1);
if(rrset == NULL) { if(rrset == NULL) {
verbose(VERB_ALGO, "rpz: qname after cname: type not found"); verbose(VERB_ALGO, "rpz: qname: type not found");
return NULL; return NULL;
} }
return rpz_synthesize_localdata_from_rrset(r, ms, qinfo, rrset, az); return rpz_synthesize_localdata_from_rrset(r, ms, qinfo, rrset, az);
} }
/** Synthesize a CNAME message for RPZ action override */
static struct dns_msg*
rpz_synthesize_cname_override_msg(struct rpz* r, struct module_qstate* ms,
struct query_info* qinfo)
{
struct dns_msg* msg = NULL;
struct reply_info* new_reply_info;
struct ub_packed_rrset_key* rp;
msg = rpz_dns_msg_new(ms->region);
if(msg == NULL) { return NULL; }
msg->qinfo = *qinfo;
new_reply_info = construct_reply_info_base(ms->region,
LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA,
1, /* qd */
0, /* ttl */
0, /* prettl */
0, /* expttl */
1, /* an */
0, /* ns */
0, /* ar */
1, /* total */
sec_status_insecure,
LDNS_EDE_NONE);
if(new_reply_info == NULL) {
log_err("out of memory");
return NULL;
}
new_reply_info->authoritative = 1;
rp = respip_copy_rrset(r->cname_override, ms->region);
if(rp == NULL) {
log_err("out of memory");
return NULL;
}
rp->rk.dname = qinfo->qname;
rp->rk.dname_len = qinfo->qname_len;
/* this rrset is from the rpz data, or synthesized.
* It is not actually from the network, so we flag it with this
* flags as a fake RRset. If later the cache is used to look up
* rrsets, then the fake ones are not returned (if you look without
* the flag). For like CNAME lookups from the iterator or A, AAAA
* lookups for nameserver targets, it would use the without flag
* actual data. So that the actual network data and fake data
* are kept track of separately. */
rp->rk.flags |= PACKED_RRSET_RPZ;
new_reply_info->rrsets[0] = rp;
msg->rep = new_reply_info;
return msg;
}
static int static int
rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r, rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
struct local_zone* z, enum localzone_type lzt, struct query_info* qinfo, struct local_zone* z, enum localzone_type lzt, struct query_info* qinfo,
@ -2072,17 +2207,8 @@ rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
struct local_data* ld = NULL; struct local_data* ld = NULL;
int ret = 0; int ret = 0;
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) { if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
qinfo->local_alias = regional_alloc_zero(temp, sizeof(struct local_rrset)); if(!rpz_apply_cname_override_action(r, qinfo, temp))
if(qinfo->local_alias == NULL) { return 0;
return 0; /* out of memory */
}
qinfo->local_alias->rrset = regional_alloc_init(temp, r->cname_override,
sizeof(*r->cname_override));
if(qinfo->local_alias->rrset == NULL) {
return 0; /* out of memory */
}
qinfo->local_alias->rrset->rk.dname = qinfo->qname;
qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
if(r->log) { if(r->log) {
log_rpz_apply("qname", z->name, NULL, RPZ_CNAME_OVERRIDE_ACTION, log_rpz_apply("qname", z->name, NULL, RPZ_CNAME_OVERRIDE_ACTION,
qinfo, repinfo, NULL, r->log_name); qinfo, repinfo, NULL, r->log_name);
@ -2134,8 +2260,9 @@ rpz_delegation_point_ipbased_trigger_lookup(struct rpz* rpz, struct iter_qstate*
} }
static struct dns_msg* static struct dns_msg*
rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r, rpz_apply_nsip_trigger(struct module_qstate* ms, struct query_info* qchase,
struct clientip_synthesized_rr* raddr, struct auth_zone* az) struct rpz* r, struct clientip_synthesized_rr* raddr,
struct auth_zone* az)
{ {
enum rpz_action action = raddr->action; enum rpz_action action = raddr->action;
struct dns_msg* ret = NULL; struct dns_msg* ret = NULL;
@ -2148,16 +2275,16 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL) { if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL) {
verbose(VERB_ALGO, "rpz: bug: nsip local data action but no local data"); verbose(VERB_ALGO, "rpz: bug: nsip local data action but no local data");
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); ret = rpz_synthesize_nodata(r, ms, qchase, az);
goto done; goto done;
} }
switch(action) { switch(action) {
case RPZ_NXDOMAIN_ACTION: case RPZ_NXDOMAIN_ACTION:
ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az); ret = rpz_synthesize_nxdomain(r, ms, qchase, az);
break; break;
case RPZ_NODATA_ACTION: case RPZ_NODATA_ACTION:
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); ret = rpz_synthesize_nodata(r, ms, qchase, az);
break; break;
case RPZ_TCP_ONLY_ACTION: case RPZ_TCP_ONLY_ACTION:
/* basically a passthru here but the tcp-only will be /* basically a passthru here but the tcp-only will be
@ -2166,17 +2293,20 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
ret = NULL; ret = NULL;
break; break;
case RPZ_DROP_ACTION: case RPZ_DROP_ACTION:
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); ret = rpz_synthesize_nodata(r, ms, qchase, az);
ms->is_drop = 1; ms->is_drop = 1;
break; break;
case RPZ_LOCAL_DATA_ACTION: case RPZ_LOCAL_DATA_ACTION:
ret = rpz_synthesize_nsip_localdata(r, ms, raddr, az); ret = rpz_synthesize_nsip_localdata(r, ms, qchase, raddr, az);
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); } if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); }
break; break;
case RPZ_PASSTHRU_ACTION: case RPZ_PASSTHRU_ACTION:
ret = NULL; ret = NULL;
ms->rpz_passthru = 1; ms->rpz_passthru = 1;
break; break;
case RPZ_CNAME_OVERRIDE_ACTION:
ret = rpz_synthesize_cname_override_msg(r, ms, qchase);
break;
default: default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
rpz_action_to_string(action)); rpz_action_to_string(action));
@ -2194,9 +2324,9 @@ done:
} }
static struct dns_msg* static struct dns_msg*
rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r, rpz_apply_nsdname_trigger(struct module_qstate* ms, struct query_info* qchase,
struct local_zone* z, struct matched_delegation_point const* match, struct rpz* r, struct local_zone* z,
struct auth_zone* az) struct matched_delegation_point const* match, struct auth_zone* az)
{ {
struct dns_msg* ret = NULL; struct dns_msg* ret = NULL;
enum rpz_action action = localzone_type_to_rpz_action(z->type); enum rpz_action action = localzone_type_to_rpz_action(z->type);
@ -2209,10 +2339,10 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
switch(action) { switch(action) {
case RPZ_NXDOMAIN_ACTION: case RPZ_NXDOMAIN_ACTION:
ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az); ret = rpz_synthesize_nxdomain(r, ms, qchase, az);
break; break;
case RPZ_NODATA_ACTION: case RPZ_NODATA_ACTION:
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); ret = rpz_synthesize_nodata(r, ms, qchase, az);
break; break;
case RPZ_TCP_ONLY_ACTION: case RPZ_TCP_ONLY_ACTION:
/* basically a passthru here but the tcp-only will be /* basically a passthru here but the tcp-only will be
@ -2221,19 +2351,22 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
ret = NULL; ret = NULL;
break; break;
case RPZ_DROP_ACTION: case RPZ_DROP_ACTION:
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); ret = rpz_synthesize_nodata(r, ms, qchase, az);
ms->is_drop = 1; ms->is_drop = 1;
break; break;
case RPZ_LOCAL_DATA_ACTION: case RPZ_LOCAL_DATA_ACTION:
ret = rpz_synthesize_nsdname_localdata(r, ms, z, match, az); ret = rpz_synthesize_nsdname_localdata(r, ms, qchase, z, match, az);
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); } if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); }
break; break;
case RPZ_PASSTHRU_ACTION: case RPZ_PASSTHRU_ACTION:
ret = NULL; ret = NULL;
ms->rpz_passthru = 1; ms->rpz_passthru = 1;
break; break;
case RPZ_CNAME_OVERRIDE_ACTION:
ret = rpz_synthesize_cname_override_msg(r, ms, qchase);
break;
default: default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", verbose(VERB_ALGO, "rpz: nsdname: bug: unhandled or invalid action: '%s'",
rpz_action_to_string(action)); rpz_action_to_string(action));
ret = NULL; ret = NULL;
} }
@ -2324,7 +2457,7 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
/* the nsdname has precedence over the nsip triggers */ /* the nsdname has precedence over the nsip triggers */
z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones, z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones,
ms->qinfo.qclass, &match); is->qchase.qclass, &match);
if(z != NULL) { if(z != NULL) {
lock_rw_unlock(&a->lock); lock_rw_unlock(&a->lock);
break; break;
@ -2347,9 +2480,9 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
if(z) { if(z) {
lock_rw_unlock(&z->lock); lock_rw_unlock(&z->lock);
} }
return rpz_apply_nsip_trigger(ms, r, raddr, a); return rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a);
} }
return rpz_apply_nsdname_trigger(ms, r, z, &match, a); return rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a);
} }
struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
@ -2412,10 +2545,10 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
dname_str(is->qchase.qname, nm); dname_str(is->qchase.qname, nm);
dname_str(z->name, zn); dname_str(z->name, zn);
if(strcmp(zn, nm) != 0) if(strcmp(zn, nm) != 0)
verbose(VERB_ALGO, "rpz: qname trigger after cname %s on %s, with action=%s", verbose(VERB_ALGO, "rpz: qname trigger %s on %s, with action=%s",
zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); zn, nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
else else
verbose(VERB_ALGO, "rpz: qname trigger after cname %s, with action=%s", verbose(VERB_ALGO, "rpz: qname trigger %s, with action=%s",
nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); nm, rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
} }
switch(localzone_type_to_rpz_action(lzt)) { switch(localzone_type_to_rpz_action(lzt)) {
@ -2444,7 +2577,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
ms->rpz_passthru = 1; ms->rpz_passthru = 1;
break; break;
default: default:
verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'", verbose(VERB_ALGO, "rpz: qname trigger: bug: unhandled or invalid action: '%s'",
rpz_action_to_string(localzone_type_to_rpz_action(lzt))); rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
ret = NULL; ret = NULL;
} }
@ -2472,8 +2605,21 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out); az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out);
client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action); client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action);
if(node != NULL && *r_out &&
(*r_out)->action_override != RPZ_NO_OVERRIDE_ACTION) {
client_action = (*r_out)->action_override;
}
if(client_action == RPZ_PASSTHRU_ACTION) { if(client_action == RPZ_PASSTHRU_ACTION) {
if(*r_out && (*r_out)->log)
log_rpz_apply(
(node?"clientip":"qname"),
((*z_out)?(*z_out)->name:NULL),
(node?&node->node:NULL),
client_action, qinfo, repinfo, NULL,
(*r_out)->log_name);
*passthru = 1; *passthru = 1;
ret = 0;
goto done;
} }
if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION && if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION &&
client_action != RPZ_PASSTHRU_ACTION)) { client_action != RPZ_PASSTHRU_ACTION)) {
@ -2488,14 +2634,15 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
if(client_action == RPZ_LOCAL_DATA_ACTION) { if(client_action == RPZ_LOCAL_DATA_ACTION) {
rpz_apply_clientip_localdata_action(node, env, qinfo, rpz_apply_clientip_localdata_action(node, env, qinfo,
edns, repinfo, buf, temp, *a_out); edns, repinfo, buf, temp, *a_out);
ret = 1;
} else if(client_action == RPZ_CNAME_OVERRIDE_ACTION) {
if(!rpz_apply_cname_override_action(*r_out, qinfo,
temp)) {
ret = 0;
goto done;
}
ret = 0;
} else { } else {
if(*r_out && (*r_out)->log)
log_rpz_apply(
(node?"clientip":"qname"),
((*z_out)?(*z_out)->name:NULL),
(node?&node->node:NULL),
client_action, qinfo, repinfo, NULL,
(*r_out)->log_name);
local_zones_zone_answer(*z_out /*likely NULL, no zone*/, env, qinfo, edns, local_zones_zone_answer(*z_out /*likely NULL, no zone*/, env, qinfo, edns,
repinfo, buf, temp, 0 /* no local data used */, repinfo, buf, temp, 0 /* no local data used */,
rpz_action_to_localzone_type(client_action)); rpz_action_to_localzone_type(client_action));
@ -2503,8 +2650,15 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
LDNS_RCODE_WIRE(sldns_buffer_begin(buf)) LDNS_RCODE_WIRE(sldns_buffer_begin(buf))
== LDNS_RCODE_NXDOMAIN) == LDNS_RCODE_NXDOMAIN)
LDNS_RA_CLR(sldns_buffer_begin(buf)); LDNS_RA_CLR(sldns_buffer_begin(buf));
ret = 1;
} }
ret = 1; if(*r_out && (*r_out)->log)
log_rpz_apply(
(node?"clientip":"qname"),
((*z_out)?(*z_out)->name:NULL),
(node?&node->node:NULL),
client_action, qinfo, repinfo, NULL,
(*r_out)->log_name);
goto done; goto done;
} }
ret = -1; ret = -1;

View file

@ -225,6 +225,14 @@ int rpz_clear(struct rpz* r);
*/ */
struct rpz* rpz_create(struct config_auth* p); struct rpz* rpz_create(struct config_auth* p);
/**
* Change config on rpz, after reload.
* @param r: the rpz structure.
* @param p: the config that was read.
* @return false on failure.
*/
int rpz_config(struct rpz* r, struct config_auth* p);
/** /**
* String for RPZ action enum * String for RPZ action enum
* @param a: RPZ action to get string for * @param a: RPZ action to get string for

View file

@ -126,7 +126,8 @@ void view_delete(struct view* v);
*/ */
void views_print(struct views* v); void views_print(struct views* v);
/* Find a view by name. /**
* Find a view by name.
* @param vs: views * @param vs: views
* @param name: name of the view we are looking for * @param name: name of the view we are looking for
* @param write: 1 for obtaining write lock on found view, 0 for read lock * @param write: 1 for obtaining write lock on found view, 0 for read lock

View file

@ -174,6 +174,7 @@ config_create(void)
cfg->min_ttl = 0; cfg->min_ttl = 0;
cfg->max_ttl = 3600 * 24; cfg->max_ttl = 3600 * 24;
cfg->max_negative_ttl = 3600; cfg->max_negative_ttl = 3600;
cfg->min_negative_ttl = 0;
cfg->prefetch = 0; cfg->prefetch = 0;
cfg->prefetch_key = 0; cfg->prefetch_key = 0;
cfg->deny_any = 0; cfg->deny_any = 0;
@ -308,6 +309,11 @@ config_create(void)
cfg->minimal_responses = 1; cfg->minimal_responses = 1;
cfg->rrset_roundrobin = 1; cfg->rrset_roundrobin = 1;
cfg->unknown_server_time_limit = 376; cfg->unknown_server_time_limit = 376;
cfg->discard_timeout = 1900; /* msec */
cfg->wait_limit = 1000;
cfg->wait_limit_cookie = 10000;
cfg->wait_limit_netblock = NULL;
cfg->wait_limit_cookie_netblock = NULL;
cfg->max_udp_size = 1232; /* value taken from edns_buffer_size */ cfg->max_udp_size = 1232; /* value taken from edns_buffer_size */
if(!(cfg->server_key_file = strdup(RUN_DIR"/unbound_server.key"))) if(!(cfg->server_key_file = strdup(RUN_DIR"/unbound_server.key")))
goto error_exit; goto error_exit;
@ -384,6 +390,7 @@ config_create(void)
if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit; if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit;
if(!(cfg->cachedb_secret = strdup("default"))) goto error_exit; if(!(cfg->cachedb_secret = strdup("default"))) goto error_exit;
cfg->cachedb_no_store = 0; cfg->cachedb_no_store = 0;
cfg->cachedb_check_when_serve_expired = 1;
#ifdef USE_REDIS #ifdef USE_REDIS
if(!(cfg->redis_server_host = strdup("127.0.0.1"))) goto error_exit; if(!(cfg->redis_server_host = strdup("127.0.0.1"))) goto error_exit;
cfg->redis_server_path = NULL; cfg->redis_server_path = NULL;
@ -615,6 +622,8 @@ int config_set_option(struct config_file* cfg, const char* opt,
{ IS_NUMBER_OR_ZERO; cfg->max_ttl = atoi(val); MAX_TTL=(time_t)cfg->max_ttl;} { IS_NUMBER_OR_ZERO; cfg->max_ttl = atoi(val); MAX_TTL=(time_t)cfg->max_ttl;}
else if(strcmp(opt, "cache-max-negative-ttl:") == 0) else if(strcmp(opt, "cache-max-negative-ttl:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->max_negative_ttl = atoi(val); MAX_NEG_TTL=(time_t)cfg->max_negative_ttl;} { IS_NUMBER_OR_ZERO; cfg->max_negative_ttl = atoi(val); MAX_NEG_TTL=(time_t)cfg->max_negative_ttl;}
else if(strcmp(opt, "cache-min-negative-ttl:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->min_negative_ttl = atoi(val); MIN_NEG_TTL=(time_t)cfg->min_negative_ttl;}
else if(strcmp(opt, "cache-min-ttl:") == 0) else if(strcmp(opt, "cache-min-ttl:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->min_ttl = atoi(val); MIN_TTL=(time_t)cfg->min_ttl;} { IS_NUMBER_OR_ZERO; cfg->min_ttl = atoi(val); MIN_TTL=(time_t)cfg->min_ttl;}
else if(strcmp(opt, "infra-cache-min-rtt:") == 0) { else if(strcmp(opt, "infra-cache-min-rtt:") == 0) {
@ -722,6 +731,9 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_YNO("minimal-responses:", minimal_responses) else S_YNO("minimal-responses:", minimal_responses)
else S_YNO("rrset-roundrobin:", rrset_roundrobin) else S_YNO("rrset-roundrobin:", rrset_roundrobin)
else S_NUMBER_OR_ZERO("unknown-server-time-limit:", unknown_server_time_limit) else S_NUMBER_OR_ZERO("unknown-server-time-limit:", unknown_server_time_limit)
else S_NUMBER_OR_ZERO("discard-timeout:", discard_timeout)
else S_NUMBER_OR_ZERO("wait-limit:", wait_limit)
else S_NUMBER_OR_ZERO("wait-limit-cookie:", wait_limit_cookie)
else S_STRLIST("local-data:", local_data) else S_STRLIST("local-data:", local_data)
else S_YNO("unblock-lan-zones:", unblock_lan_zones) else S_YNO("unblock-lan-zones:", unblock_lan_zones)
else S_YNO("insecure-lan-zones:", insecure_lan_zones) else S_YNO("insecure-lan-zones:", insecure_lan_zones)
@ -827,6 +839,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
#endif #endif
#ifdef USE_CACHEDB #ifdef USE_CACHEDB
else S_YNO("cachedb-no-store:", cachedb_no_store) else S_YNO("cachedb-no-store:", cachedb_no_store)
else S_YNO("cachedb-check-when-serve-expired:", cachedb_check_when_serve_expired)
#endif /* USE_CACHEDB */ #endif /* USE_CACHEDB */
else if(strcmp(opt, "define-tag:") ==0) { else if(strcmp(opt, "define-tag:") ==0) {
return config_add_tag(cfg, val); return config_add_tag(cfg, val);
@ -1065,6 +1078,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_YNO(opt, "deny-any", deny_any) else O_YNO(opt, "deny-any", deny_any)
else O_DEC(opt, "cache-max-ttl", max_ttl) else O_DEC(opt, "cache-max-ttl", max_ttl)
else O_DEC(opt, "cache-max-negative-ttl", max_negative_ttl) else O_DEC(opt, "cache-max-negative-ttl", max_negative_ttl)
else O_DEC(opt, "cache-min-negative-ttl", min_negative_ttl)
else O_DEC(opt, "cache-min-ttl", min_ttl) else O_DEC(opt, "cache-min-ttl", min_ttl)
else O_DEC(opt, "infra-host-ttl", host_ttl) else O_DEC(opt, "infra-host-ttl", host_ttl)
else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs) else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs)
@ -1201,6 +1215,11 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_YNO(opt, "minimal-responses", minimal_responses) else O_YNO(opt, "minimal-responses", minimal_responses)
else O_YNO(opt, "rrset-roundrobin", rrset_roundrobin) else O_YNO(opt, "rrset-roundrobin", rrset_roundrobin)
else O_DEC(opt, "unknown-server-time-limit", unknown_server_time_limit) else O_DEC(opt, "unknown-server-time-limit", unknown_server_time_limit)
else O_DEC(opt, "discard-timeout", discard_timeout)
else O_DEC(opt, "wait-limit", wait_limit)
else O_DEC(opt, "wait-limit-cookie", wait_limit_cookie)
else O_LS2(opt, "wait-limit-netblock", wait_limit_netblock)
else O_LS2(opt, "wait-limit-cookie-netblock", wait_limit_cookie_netblock)
#ifdef CLIENT_SUBNET #ifdef CLIENT_SUBNET
else O_LST(opt, "send-client-subnet", client_subnet) else O_LST(opt, "send-client-subnet", client_subnet)
else O_LST(opt, "client-subnet-zone", client_subnet_zone) else O_LST(opt, "client-subnet-zone", client_subnet_zone)
@ -1318,6 +1337,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_STR(opt, "backend", cachedb_backend) else O_STR(opt, "backend", cachedb_backend)
else O_STR(opt, "secret-seed", cachedb_secret) else O_STR(opt, "secret-seed", cachedb_secret)
else O_YNO(opt, "cachedb-no-store", cachedb_no_store) else O_YNO(opt, "cachedb-no-store", cachedb_no_store)
else O_YNO(opt, "cachedb-check-when-serve-expired", cachedb_check_when_serve_expired)
#ifdef USE_REDIS #ifdef USE_REDIS
else O_STR(opt, "redis-server-host", redis_server_host) else O_STR(opt, "redis-server-host", redis_server_host)
else O_DEC(opt, "redis-server-port", redis_server_port) else O_DEC(opt, "redis-server-port", redis_server_port)
@ -1671,6 +1691,8 @@ config_delete(struct config_file* cfg)
config_deltrplstrlist(cfg->interface_tag_actions); config_deltrplstrlist(cfg->interface_tag_actions);
config_deltrplstrlist(cfg->interface_tag_datas); config_deltrplstrlist(cfg->interface_tag_datas);
config_delstrlist(cfg->control_ifs.first); config_delstrlist(cfg->control_ifs.first);
config_deldblstrlist(cfg->wait_limit_netblock);
config_deldblstrlist(cfg->wait_limit_cookie_netblock);
free(cfg->server_key_file); free(cfg->server_key_file);
free(cfg->server_cert_file); free(cfg->server_cert_file);
free(cfg->control_key_file); free(cfg->control_key_file);
@ -1761,6 +1783,10 @@ cfg_mark_ports(const char* str, int allow, int* avail, int num)
#endif #endif
if(!mid) { if(!mid) {
int port = atoi(str); int port = atoi(str);
if(port < 0) {
log_err("port number is negative: %d", port);
return 0;
}
if(port == 0 && strcmp(str, "0") != 0) { if(port == 0 && strcmp(str, "0") != 0) {
log_err("cannot parse port number '%s'", str); log_err("cannot parse port number '%s'", str);
return 0; return 0;
@ -1770,6 +1796,10 @@ cfg_mark_ports(const char* str, int allow, int* avail, int num)
} else { } else {
int i, low, high = atoi(mid+1); int i, low, high = atoi(mid+1);
char buf[16]; char buf[16];
if(high < 0) {
log_err("port number is negative: %d", high);
return 0;
}
if(high == 0 && strcmp(mid+1, "0") != 0) { if(high == 0 && strcmp(mid+1, "0") != 0) {
log_err("cannot parse port number '%s'", mid+1); log_err("cannot parse port number '%s'", mid+1);
return 0; return 0;
@ -1782,10 +1812,18 @@ cfg_mark_ports(const char* str, int allow, int* avail, int num)
memcpy(buf, str, (size_t)(mid-str)); memcpy(buf, str, (size_t)(mid-str));
buf[mid-str] = 0; buf[mid-str] = 0;
low = atoi(buf); low = atoi(buf);
if(low < 0) {
log_err("port number is negative: %d", low);
return 0;
}
if(low == 0 && strcmp(buf, "0") != 0) { if(low == 0 && strcmp(buf, "0") != 0) {
log_err("cannot parse port number '%s'", buf); log_err("cannot parse port number '%s'", buf);
return 0; return 0;
} }
if(high > num) {
/* Stop very high values from taking a long time. */
high = num;
}
for(i=low; i<=high; i++) { for(i=low; i<=high; i++) {
if(i < num) if(i < num)
avail[i] = (allow?i:0); avail[i] = (allow?i:0);
@ -2310,6 +2348,7 @@ config_apply(struct config_file* config)
SERVE_EXPIRED_REPLY_TTL = (time_t)config->serve_expired_reply_ttl; SERVE_EXPIRED_REPLY_TTL = (time_t)config->serve_expired_reply_ttl;
SERVE_ORIGINAL_TTL = config->serve_original_ttl; SERVE_ORIGINAL_TTL = config->serve_original_ttl;
MAX_NEG_TTL = (time_t)config->max_negative_ttl; MAX_NEG_TTL = (time_t)config->max_negative_ttl;
MIN_NEG_TTL = (time_t)config->min_negative_ttl;
RTT_MIN_TIMEOUT = config->infra_cache_min_rtt; RTT_MIN_TIMEOUT = config->infra_cache_min_rtt;
RTT_MAX_TIMEOUT = config->infra_cache_max_rtt; RTT_MAX_TIMEOUT = config->infra_cache_max_rtt;
EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size; EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;

View file

@ -315,6 +315,8 @@ struct config_file {
int min_ttl; int min_ttl;
/** the number of seconds maximal negative TTL for SOA in auth */ /** the number of seconds maximal negative TTL for SOA in auth */
int max_negative_ttl; int max_negative_ttl;
/** the number of seconds minimal negative TTL for SOA in auth */
int min_negative_ttl;
/** if prefetching of messages should be performed. */ /** if prefetching of messages should be performed. */
int prefetch; int prefetch;
/** if prefetching of DNSKEYs should be performed. */ /** if prefetching of DNSKEYs should be performed. */
@ -535,6 +537,21 @@ struct config_file {
/* wait time for unknown server in msec */ /* wait time for unknown server in msec */
int unknown_server_time_limit; int unknown_server_time_limit;
/** Wait time to drop recursion replies */
int discard_timeout;
/** Wait limit for number of replies per IP address */
int wait_limit;
/** Wait limit for number of replies per IP address with cookie */
int wait_limit_cookie;
/** wait limit per netblock */
struct config_str2list* wait_limit_netblock;
/** wait limit with cookie per netblock */
struct config_str2list* wait_limit_cookie_netblock;
/* maximum UDP response size */ /* maximum UDP response size */
size_t max_udp_size; size_t max_udp_size;
@ -705,6 +722,8 @@ struct config_file {
char* cachedb_secret; char* cachedb_secret;
/** cachedb that does not store, but only reads from database, if on */ /** cachedb that does not store, but only reads from database, if on */
int cachedb_no_store; int cachedb_no_store;
/** cachedb check before serving serve-expired response */
int cachedb_check_when_serve_expired;
#ifdef USE_REDIS #ifdef USE_REDIS
/** redis server's IP address or host name */ /** redis server's IP address or host name */
char* redis_server_host; char* redis_server_host;

File diff suppressed because it is too large Load diff

View file

@ -297,6 +297,7 @@ rrset-cache-size{COLON} { YDVAR(1, VAR_RRSET_CACHE_SIZE) }
rrset-cache-slabs{COLON} { YDVAR(1, VAR_RRSET_CACHE_SLABS) } rrset-cache-slabs{COLON} { YDVAR(1, VAR_RRSET_CACHE_SLABS) }
cache-max-ttl{COLON} { YDVAR(1, VAR_CACHE_MAX_TTL) } cache-max-ttl{COLON} { YDVAR(1, VAR_CACHE_MAX_TTL) }
cache-max-negative-ttl{COLON} { YDVAR(1, VAR_CACHE_MAX_NEGATIVE_TTL) } cache-max-negative-ttl{COLON} { YDVAR(1, VAR_CACHE_MAX_NEGATIVE_TTL) }
cache-min-negative-ttl{COLON} { YDVAR(1, VAR_CACHE_MIN_NEGATIVE_TTL) }
cache-min-ttl{COLON} { YDVAR(1, VAR_CACHE_MIN_TTL) } cache-min-ttl{COLON} { YDVAR(1, VAR_CACHE_MIN_TTL) }
infra-host-ttl{COLON} { YDVAR(1, VAR_INFRA_HOST_TTL) } infra-host-ttl{COLON} { YDVAR(1, VAR_INFRA_HOST_TTL) }
infra-lame-ttl{COLON} { YDVAR(1, VAR_INFRA_LAME_TTL) } infra-lame-ttl{COLON} { YDVAR(1, VAR_INFRA_LAME_TTL) }
@ -463,6 +464,11 @@ domain-insecure{COLON} { YDVAR(1, VAR_DOMAIN_INSECURE) }
minimal-responses{COLON} { YDVAR(1, VAR_MINIMAL_RESPONSES) } minimal-responses{COLON} { YDVAR(1, VAR_MINIMAL_RESPONSES) }
rrset-roundrobin{COLON} { YDVAR(1, VAR_RRSET_ROUNDROBIN) } rrset-roundrobin{COLON} { YDVAR(1, VAR_RRSET_ROUNDROBIN) }
unknown-server-time-limit{COLON} { YDVAR(1, VAR_UNKNOWN_SERVER_TIME_LIMIT) } unknown-server-time-limit{COLON} { YDVAR(1, VAR_UNKNOWN_SERVER_TIME_LIMIT) }
discard-timeout{COLON} { YDVAR(1, VAR_DISCARD_TIMEOUT) }
wait-limit{COLON} { YDVAR(1, VAR_WAIT_LIMIT) }
wait-limit-cookie{COLON} { YDVAR(1, VAR_WAIT_LIMIT_COOKIE) }
wait-limit-netblock{COLON} { YDVAR(1, VAR_WAIT_LIMIT_NETBLOCK) }
wait-limit-cookie-netblock{COLON} { YDVAR(1, VAR_WAIT_LIMIT_COOKIE_NETBLOCK) }
max-udp-size{COLON} { YDVAR(1, VAR_MAX_UDP_SIZE) } max-udp-size{COLON} { YDVAR(1, VAR_MAX_UDP_SIZE) }
dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) } dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) }
dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) } dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) }
@ -560,6 +566,7 @@ cachedb{COLON} { YDVAR(0, VAR_CACHEDB) }
backend{COLON} { YDVAR(1, VAR_CACHEDB_BACKEND) } backend{COLON} { YDVAR(1, VAR_CACHEDB_BACKEND) }
secret-seed{COLON} { YDVAR(1, VAR_CACHEDB_SECRETSEED) } secret-seed{COLON} { YDVAR(1, VAR_CACHEDB_SECRETSEED) }
cachedb-no-store{COLON} { YDVAR(1, VAR_CACHEDB_NO_STORE) } cachedb-no-store{COLON} { YDVAR(1, VAR_CACHEDB_NO_STORE) }
cachedb-check-when-serve-expired{COLON} { YDVAR(1, VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED) }
redis-server-host{COLON} { YDVAR(1, VAR_CACHEDB_REDISHOST) } redis-server-host{COLON} { YDVAR(1, VAR_CACHEDB_REDISHOST) }
redis-server-port{COLON} { YDVAR(1, VAR_CACHEDB_REDISPORT) } redis-server-port{COLON} { YDVAR(1, VAR_CACHEDB_REDISPORT) }
redis-server-path{COLON} { YDVAR(1, VAR_CACHEDB_REDISPATH) } redis-server-path{COLON} { YDVAR(1, VAR_CACHEDB_REDISPATH) }

View file

@ -222,129 +222,136 @@
#define VAR_CAPS_WHITELIST 478 #define VAR_CAPS_WHITELIST 478
#define VAR_CACHE_MAX_NEGATIVE_TTL 479 #define VAR_CACHE_MAX_NEGATIVE_TTL 479
#define VAR_PERMIT_SMALL_HOLDDOWN 480 #define VAR_PERMIT_SMALL_HOLDDOWN 480
#define VAR_QNAME_MINIMISATION 481 #define VAR_CACHE_MIN_NEGATIVE_TTL 481
#define VAR_QNAME_MINIMISATION_STRICT 482 #define VAR_QNAME_MINIMISATION 482
#define VAR_IP_FREEBIND 483 #define VAR_QNAME_MINIMISATION_STRICT 483
#define VAR_DEFINE_TAG 484 #define VAR_IP_FREEBIND 484
#define VAR_LOCAL_ZONE_TAG 485 #define VAR_DEFINE_TAG 485
#define VAR_ACCESS_CONTROL_TAG 486 #define VAR_LOCAL_ZONE_TAG 486
#define VAR_LOCAL_ZONE_OVERRIDE 487 #define VAR_ACCESS_CONTROL_TAG 487
#define VAR_ACCESS_CONTROL_TAG_ACTION 488 #define VAR_LOCAL_ZONE_OVERRIDE 488
#define VAR_ACCESS_CONTROL_TAG_DATA 489 #define VAR_ACCESS_CONTROL_TAG_ACTION 489
#define VAR_VIEW 490 #define VAR_ACCESS_CONTROL_TAG_DATA 490
#define VAR_ACCESS_CONTROL_VIEW 491 #define VAR_VIEW 491
#define VAR_VIEW_FIRST 492 #define VAR_ACCESS_CONTROL_VIEW 492
#define VAR_SERVE_EXPIRED 493 #define VAR_VIEW_FIRST 493
#define VAR_SERVE_EXPIRED_TTL 494 #define VAR_SERVE_EXPIRED 494
#define VAR_SERVE_EXPIRED_TTL_RESET 495 #define VAR_SERVE_EXPIRED_TTL 495
#define VAR_SERVE_EXPIRED_REPLY_TTL 496 #define VAR_SERVE_EXPIRED_TTL_RESET 496
#define VAR_SERVE_EXPIRED_CLIENT_TIMEOUT 497 #define VAR_SERVE_EXPIRED_REPLY_TTL 497
#define VAR_EDE_SERVE_EXPIRED 498 #define VAR_SERVE_EXPIRED_CLIENT_TIMEOUT 498
#define VAR_SERVE_ORIGINAL_TTL 499 #define VAR_EDE_SERVE_EXPIRED 499
#define VAR_FAKE_DSA 500 #define VAR_SERVE_ORIGINAL_TTL 500
#define VAR_FAKE_SHA1 501 #define VAR_FAKE_DSA 501
#define VAR_LOG_IDENTITY 502 #define VAR_FAKE_SHA1 502
#define VAR_HIDE_TRUSTANCHOR 503 #define VAR_LOG_IDENTITY 503
#define VAR_HIDE_HTTP_USER_AGENT 504 #define VAR_HIDE_TRUSTANCHOR 504
#define VAR_HTTP_USER_AGENT 505 #define VAR_HIDE_HTTP_USER_AGENT 505
#define VAR_TRUST_ANCHOR_SIGNALING 506 #define VAR_HTTP_USER_AGENT 506
#define VAR_AGGRESSIVE_NSEC 507 #define VAR_TRUST_ANCHOR_SIGNALING 507
#define VAR_USE_SYSTEMD 508 #define VAR_AGGRESSIVE_NSEC 508
#define VAR_SHM_ENABLE 509 #define VAR_USE_SYSTEMD 509
#define VAR_SHM_KEY 510 #define VAR_SHM_ENABLE 510
#define VAR_ROOT_KEY_SENTINEL 511 #define VAR_SHM_KEY 511
#define VAR_DNSCRYPT 512 #define VAR_ROOT_KEY_SENTINEL 512
#define VAR_DNSCRYPT_ENABLE 513 #define VAR_DNSCRYPT 513
#define VAR_DNSCRYPT_PORT 514 #define VAR_DNSCRYPT_ENABLE 514
#define VAR_DNSCRYPT_PROVIDER 515 #define VAR_DNSCRYPT_PORT 515
#define VAR_DNSCRYPT_SECRET_KEY 516 #define VAR_DNSCRYPT_PROVIDER 516
#define VAR_DNSCRYPT_PROVIDER_CERT 517 #define VAR_DNSCRYPT_SECRET_KEY 517
#define VAR_DNSCRYPT_PROVIDER_CERT_ROTATED 518 #define VAR_DNSCRYPT_PROVIDER_CERT 518
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE 519 #define VAR_DNSCRYPT_PROVIDER_CERT_ROTATED 519
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS 520 #define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE 520
#define VAR_DNSCRYPT_NONCE_CACHE_SIZE 521 #define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS 521
#define VAR_DNSCRYPT_NONCE_CACHE_SLABS 522 #define VAR_DNSCRYPT_NONCE_CACHE_SIZE 522
#define VAR_PAD_RESPONSES 523 #define VAR_DNSCRYPT_NONCE_CACHE_SLABS 523
#define VAR_PAD_RESPONSES_BLOCK_SIZE 524 #define VAR_PAD_RESPONSES 524
#define VAR_PAD_QUERIES 525 #define VAR_PAD_RESPONSES_BLOCK_SIZE 525
#define VAR_PAD_QUERIES_BLOCK_SIZE 526 #define VAR_PAD_QUERIES 526
#define VAR_IPSECMOD_ENABLED 527 #define VAR_PAD_QUERIES_BLOCK_SIZE 527
#define VAR_IPSECMOD_HOOK 528 #define VAR_IPSECMOD_ENABLED 528
#define VAR_IPSECMOD_IGNORE_BOGUS 529 #define VAR_IPSECMOD_HOOK 529
#define VAR_IPSECMOD_MAX_TTL 530 #define VAR_IPSECMOD_IGNORE_BOGUS 530
#define VAR_IPSECMOD_WHITELIST 531 #define VAR_IPSECMOD_MAX_TTL 531
#define VAR_IPSECMOD_STRICT 532 #define VAR_IPSECMOD_WHITELIST 532
#define VAR_CACHEDB 533 #define VAR_IPSECMOD_STRICT 533
#define VAR_CACHEDB_BACKEND 534 #define VAR_CACHEDB 534
#define VAR_CACHEDB_SECRETSEED 535 #define VAR_CACHEDB_BACKEND 535
#define VAR_CACHEDB_REDISHOST 536 #define VAR_CACHEDB_SECRETSEED 536
#define VAR_CACHEDB_REDISPORT 537 #define VAR_CACHEDB_REDISHOST 537
#define VAR_CACHEDB_REDISTIMEOUT 538 #define VAR_CACHEDB_REDISPORT 538
#define VAR_CACHEDB_REDISEXPIRERECORDS 539 #define VAR_CACHEDB_REDISTIMEOUT 539
#define VAR_CACHEDB_REDISPATH 540 #define VAR_CACHEDB_REDISEXPIRERECORDS 540
#define VAR_CACHEDB_REDISPASSWORD 541 #define VAR_CACHEDB_REDISPATH 541
#define VAR_CACHEDB_REDISLOGICALDB 542 #define VAR_CACHEDB_REDISPASSWORD 542
#define VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM 543 #define VAR_CACHEDB_REDISLOGICALDB 543
#define VAR_FOR_UPSTREAM 544 #define VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM 544
#define VAR_AUTH_ZONE 545 #define VAR_FOR_UPSTREAM 545
#define VAR_ZONEFILE 546 #define VAR_AUTH_ZONE 546
#define VAR_MASTER 547 #define VAR_ZONEFILE 547
#define VAR_URL 548 #define VAR_MASTER 548
#define VAR_FOR_DOWNSTREAM 549 #define VAR_URL 549
#define VAR_FALLBACK_ENABLED 550 #define VAR_FOR_DOWNSTREAM 550
#define VAR_TLS_ADDITIONAL_PORT 551 #define VAR_FALLBACK_ENABLED 551
#define VAR_LOW_RTT 552 #define VAR_TLS_ADDITIONAL_PORT 552
#define VAR_LOW_RTT_PERMIL 553 #define VAR_LOW_RTT 553
#define VAR_FAST_SERVER_PERMIL 554 #define VAR_LOW_RTT_PERMIL 554
#define VAR_FAST_SERVER_NUM 555 #define VAR_FAST_SERVER_PERMIL 555
#define VAR_ALLOW_NOTIFY 556 #define VAR_FAST_SERVER_NUM 556
#define VAR_TLS_WIN_CERT 557 #define VAR_ALLOW_NOTIFY 557
#define VAR_TCP_CONNECTION_LIMIT 558 #define VAR_TLS_WIN_CERT 558
#define VAR_ANSWER_COOKIE 559 #define VAR_TCP_CONNECTION_LIMIT 559
#define VAR_COOKIE_SECRET 560 #define VAR_ANSWER_COOKIE 560
#define VAR_IP_RATELIMIT_COOKIE 561 #define VAR_COOKIE_SECRET 561
#define VAR_FORWARD_NO_CACHE 562 #define VAR_IP_RATELIMIT_COOKIE 562
#define VAR_STUB_NO_CACHE 563 #define VAR_FORWARD_NO_CACHE 563
#define VAR_LOG_SERVFAIL 564 #define VAR_STUB_NO_CACHE 564
#define VAR_DENY_ANY 565 #define VAR_LOG_SERVFAIL 565
#define VAR_UNKNOWN_SERVER_TIME_LIMIT 566 #define VAR_DENY_ANY 566
#define VAR_LOG_TAG_QUERYREPLY 567 #define VAR_UNKNOWN_SERVER_TIME_LIMIT 567
#define VAR_STREAM_WAIT_SIZE 568 #define VAR_LOG_TAG_QUERYREPLY 568
#define VAR_TLS_CIPHERS 569 #define VAR_DISCARD_TIMEOUT 569
#define VAR_TLS_CIPHERSUITES 570 #define VAR_WAIT_LIMIT 570
#define VAR_TLS_USE_SNI 571 #define VAR_WAIT_LIMIT_COOKIE 571
#define VAR_IPSET 572 #define VAR_WAIT_LIMIT_NETBLOCK 572
#define VAR_IPSET_NAME_V4 573 #define VAR_WAIT_LIMIT_COOKIE_NETBLOCK 573
#define VAR_IPSET_NAME_V6 574 #define VAR_STREAM_WAIT_SIZE 574
#define VAR_TLS_SESSION_TICKET_KEYS 575 #define VAR_TLS_CIPHERS 575
#define VAR_RPZ 576 #define VAR_TLS_CIPHERSUITES 576
#define VAR_TAGS 577 #define VAR_TLS_USE_SNI 577
#define VAR_RPZ_ACTION_OVERRIDE 578 #define VAR_IPSET 578
#define VAR_RPZ_CNAME_OVERRIDE 579 #define VAR_IPSET_NAME_V4 579
#define VAR_RPZ_LOG 580 #define VAR_IPSET_NAME_V6 580
#define VAR_RPZ_LOG_NAME 581 #define VAR_TLS_SESSION_TICKET_KEYS 581
#define VAR_DYNLIB 582 #define VAR_RPZ 582
#define VAR_DYNLIB_FILE 583 #define VAR_TAGS 583
#define VAR_EDNS_CLIENT_STRING 584 #define VAR_RPZ_ACTION_OVERRIDE 584
#define VAR_EDNS_CLIENT_STRING_OPCODE 585 #define VAR_RPZ_CNAME_OVERRIDE 585
#define VAR_NSID 586 #define VAR_RPZ_LOG 586
#define VAR_ZONEMD_PERMISSIVE_MODE 587 #define VAR_RPZ_LOG_NAME 587
#define VAR_ZONEMD_CHECK 588 #define VAR_DYNLIB 588
#define VAR_ZONEMD_REJECT_ABSENCE 589 #define VAR_DYNLIB_FILE 589
#define VAR_RPZ_SIGNAL_NXDOMAIN_RA 590 #define VAR_EDNS_CLIENT_STRING 590
#define VAR_INTERFACE_AUTOMATIC_PORTS 591 #define VAR_EDNS_CLIENT_STRING_OPCODE 591
#define VAR_EDE 592 #define VAR_NSID 592
#define VAR_INTERFACE_ACTION 593 #define VAR_ZONEMD_PERMISSIVE_MODE 593
#define VAR_INTERFACE_VIEW 594 #define VAR_ZONEMD_CHECK 594
#define VAR_INTERFACE_TAG 595 #define VAR_ZONEMD_REJECT_ABSENCE 595
#define VAR_INTERFACE_TAG_ACTION 596 #define VAR_RPZ_SIGNAL_NXDOMAIN_RA 596
#define VAR_INTERFACE_TAG_DATA 597 #define VAR_INTERFACE_AUTOMATIC_PORTS 597
#define VAR_PROXY_PROTOCOL_PORT 598 #define VAR_EDE 598
#define VAR_STATISTICS_INHIBIT_ZERO 599 #define VAR_INTERFACE_ACTION 599
#define VAR_HARDEN_UNKNOWN_ADDITIONAL 600 #define VAR_INTERFACE_VIEW 600
#define VAR_DISABLE_EDNS_DO 601 #define VAR_INTERFACE_TAG 601
#define VAR_CACHEDB_NO_STORE 602 #define VAR_INTERFACE_TAG_ACTION 602
#define VAR_LOG_DESTADDR 603 #define VAR_INTERFACE_TAG_DATA 603
#define VAR_PROXY_PROTOCOL_PORT 604
#define VAR_STATISTICS_INHIBIT_ZERO 605
#define VAR_HARDEN_UNKNOWN_ADDITIONAL 606
#define VAR_DISABLE_EDNS_DO 607
#define VAR_CACHEDB_NO_STORE 608
#define VAR_LOG_DESTADDR 609
#define VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED 610
#ifndef YYSTYPE_DEFINED #ifndef YYSTYPE_DEFINED
#define YYSTYPE_DEFINED #define YYSTYPE_DEFINED
typedef union { typedef union {

View file

@ -153,6 +153,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_MIN_CLIENT_SUBNET_IPV4 VAR_MIN_CLIENT_SUBNET_IPV6 %token VAR_MIN_CLIENT_SUBNET_IPV4 VAR_MIN_CLIENT_SUBNET_IPV6
%token VAR_MAX_ECS_TREE_SIZE_IPV4 VAR_MAX_ECS_TREE_SIZE_IPV6 %token VAR_MAX_ECS_TREE_SIZE_IPV4 VAR_MAX_ECS_TREE_SIZE_IPV6
%token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL VAR_PERMIT_SMALL_HOLDDOWN %token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL VAR_PERMIT_SMALL_HOLDDOWN
%token VAR_CACHE_MIN_NEGATIVE_TTL
%token VAR_QNAME_MINIMISATION VAR_QNAME_MINIMISATION_STRICT VAR_IP_FREEBIND %token VAR_QNAME_MINIMISATION VAR_QNAME_MINIMISATION_STRICT VAR_IP_FREEBIND
%token VAR_DEFINE_TAG VAR_LOCAL_ZONE_TAG VAR_ACCESS_CONTROL_TAG %token VAR_DEFINE_TAG VAR_LOCAL_ZONE_TAG VAR_ACCESS_CONTROL_TAG
%token VAR_LOCAL_ZONE_OVERRIDE VAR_ACCESS_CONTROL_TAG_ACTION %token VAR_LOCAL_ZONE_OVERRIDE VAR_ACCESS_CONTROL_TAG_ACTION
@ -188,6 +189,8 @@ extern struct config_parser_state* cfg_parser;
%token VAR_ANSWER_COOKIE VAR_COOKIE_SECRET VAR_IP_RATELIMIT_COOKIE %token VAR_ANSWER_COOKIE VAR_COOKIE_SECRET VAR_IP_RATELIMIT_COOKIE
%token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY %token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY
%token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY %token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY
%token VAR_DISCARD_TIMEOUT VAR_WAIT_LIMIT VAR_WAIT_LIMIT_COOKIE
%token VAR_WAIT_LIMIT_NETBLOCK VAR_WAIT_LIMIT_COOKIE_NETBLOCK
%token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES VAR_TLS_USE_SNI %token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES VAR_TLS_USE_SNI
%token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6 %token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6
%token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE %token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE
@ -200,7 +203,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_INTERFACE_TAG_ACTION VAR_INTERFACE_TAG_DATA %token VAR_INTERFACE_TAG_ACTION VAR_INTERFACE_TAG_DATA
%token VAR_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO %token VAR_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO
%token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE %token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE
%token VAR_LOG_DESTADDR %token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED
%% %%
toplevelvars: /* empty */ | toplevelvars toplevelvar ; toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -298,6 +301,7 @@ content_server: server_num_threads | server_verbosity | server_port |
server_min_client_subnet_ipv4 | server_min_client_subnet_ipv6 | server_min_client_subnet_ipv4 | server_min_client_subnet_ipv6 |
server_max_ecs_tree_size_ipv4 | server_max_ecs_tree_size_ipv6 | server_max_ecs_tree_size_ipv4 | server_max_ecs_tree_size_ipv6 |
server_caps_whitelist | server_cache_max_negative_ttl | server_caps_whitelist | server_cache_max_negative_ttl |
server_cache_min_negative_ttl |
server_permit_small_holddown | server_qname_minimisation | server_permit_small_holddown | server_qname_minimisation |
server_ip_freebind | server_define_tag | server_local_zone_tag | server_ip_freebind | server_define_tag | server_local_zone_tag |
server_disable_dnssec_lame_check | server_access_control_tag | server_disable_dnssec_lame_check | server_access_control_tag |
@ -325,6 +329,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_fast_server_permil | server_fast_server_num | server_tls_win_cert | server_fast_server_permil | server_fast_server_num | server_tls_win_cert |
server_tcp_connection_limit | server_log_servfail | server_deny_any | server_tcp_connection_limit | server_log_servfail | server_deny_any |
server_unknown_server_time_limit | server_log_tag_queryreply | server_unknown_server_time_limit | server_log_tag_queryreply |
server_discard_timeout | server_wait_limit | server_wait_limit_cookie |
server_wait_limit_netblock | server_wait_limit_cookie_netblock |
server_stream_wait_size | server_tls_ciphers | server_stream_wait_size | server_tls_ciphers |
server_tls_ciphersuites | server_tls_session_ticket_keys | server_tls_ciphersuites | server_tls_session_ticket_keys |
server_answer_cookie | server_cookie_secret | server_ip_ratelimit_cookie | server_answer_cookie | server_cookie_secret | server_ip_ratelimit_cookie |
@ -2014,6 +2020,15 @@ server_cache_max_negative_ttl: VAR_CACHE_MAX_NEGATIVE_TTL STRING_ARG
free($2); free($2);
} }
; ;
server_cache_min_negative_ttl: VAR_CACHE_MIN_NEGATIVE_TTL STRING_ARG
{
OUTYY(("P(server_cache_min_negative_ttl:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->min_negative_ttl = atoi($2);
free($2);
}
;
server_cache_min_ttl: VAR_CACHE_MIN_TTL STRING_ARG server_cache_min_ttl: VAR_CACHE_MIN_TTL STRING_ARG
{ {
OUTYY(("P(server_cache_min_ttl:%s)\n", $2)); OUTYY(("P(server_cache_min_ttl:%s)\n", $2));
@ -2366,6 +2381,57 @@ server_unknown_server_time_limit: VAR_UNKNOWN_SERVER_TIME_LIMIT STRING_ARG
free($2); free($2);
} }
; ;
server_discard_timeout: VAR_DISCARD_TIMEOUT STRING_ARG
{
OUTYY(("P(server_discard_timeout:%s)\n", $2));
cfg_parser->cfg->discard_timeout = atoi($2);
free($2);
}
;
server_wait_limit: VAR_WAIT_LIMIT STRING_ARG
{
OUTYY(("P(server_wait_limit:%s)\n", $2));
cfg_parser->cfg->wait_limit = atoi($2);
free($2);
}
;
server_wait_limit_cookie: VAR_WAIT_LIMIT_COOKIE STRING_ARG
{
OUTYY(("P(server_wait_limit_cookie:%s)\n", $2));
cfg_parser->cfg->wait_limit_cookie = atoi($2);
free($2);
}
;
server_wait_limit_netblock: VAR_WAIT_LIMIT_NETBLOCK STRING_ARG STRING_ARG
{
OUTYY(("P(server_wait_limit_netblock:%s %s)\n", $2, $3));
if(atoi($3) == 0 && strcmp($3, "0") != 0) {
yyerror("number expected");
free($2);
free($3);
} else {
if(!cfg_str2list_insert(&cfg_parser->cfg->
wait_limit_netblock, $2, $3))
fatal_exit("out of memory adding "
"wait-limit-netblock");
}
}
;
server_wait_limit_cookie_netblock: VAR_WAIT_LIMIT_COOKIE_NETBLOCK STRING_ARG STRING_ARG
{
OUTYY(("P(server_wait_limit_cookie_netblock:%s %s)\n", $2, $3));
if(atoi($3) == 0 && strcmp($3, "0") != 0) {
yyerror("number expected");
free($2);
free($3);
} else {
if(!cfg_str2list_insert(&cfg_parser->cfg->
wait_limit_cookie_netblock, $2, $3))
fatal_exit("out of memory adding "
"wait-limit-cookie-netblock");
}
}
;
server_max_udp_size: VAR_MAX_UDP_SIZE STRING_ARG server_max_udp_size: VAR_MAX_UDP_SIZE STRING_ARG
{ {
OUTYY(("P(server_max_udp_size:%s)\n", $2)); OUTYY(("P(server_max_udp_size:%s)\n", $2));
@ -3723,7 +3789,7 @@ contents_cachedb: contents_cachedb content_cachedb
content_cachedb: cachedb_backend_name | cachedb_secret_seed | content_cachedb: cachedb_backend_name | cachedb_secret_seed |
redis_server_host | redis_server_port | redis_timeout | 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 |
cachedb_no_store | redis_logical_db cachedb_no_store | redis_logical_db | cachedb_check_when_serve_expired
; ;
cachedb_backend_name: VAR_CACHEDB_BACKEND STRING_ARG cachedb_backend_name: VAR_CACHEDB_BACKEND STRING_ARG
{ {
@ -3762,6 +3828,19 @@ cachedb_no_store: VAR_CACHEDB_NO_STORE STRING_ARG
free($2); free($2);
} }
; ;
cachedb_check_when_serve_expired: VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED STRING_ARG
{
#ifdef USE_CACHEDB
OUTYY(("P(cachedb_check_when_serve_expired:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->cachedb_check_when_serve_expired = (strcmp($2, "yes")==0);
#else
OUTYY(("P(Compiled without cachedb, ignoring)\n"));
#endif
free($2);
}
;
redis_server_host: VAR_CACHEDB_REDISHOST STRING_ARG redis_server_host: VAR_CACHEDB_REDISHOST STRING_ARG
{ {
#if defined(USE_CACHEDB) && defined(USE_REDIS) #if defined(USE_CACHEDB) && defined(USE_REDIS)

View file

@ -82,6 +82,8 @@ extern time_t MAX_TTL;
extern time_t MIN_TTL; extern time_t MIN_TTL;
/** Maximum Negative TTL that is allowed */ /** Maximum Negative TTL that is allowed */
extern time_t MAX_NEG_TTL; extern time_t MAX_NEG_TTL;
/** Minimum Negative TTL that is allowed */
extern time_t MIN_NEG_TTL;
/** If we serve expired entries and prefetch them */ /** If we serve expired entries and prefetch them */
extern int SERVE_EXPIRED; extern int SERVE_EXPIRED;
/** Time to serve records after expiration */ /** Time to serve records after expiration */

View file

@ -61,6 +61,8 @@ time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
time_t MIN_TTL = 0; time_t MIN_TTL = 0;
/** MAX Negative TTL, for SOA records in authority section */ /** MAX Negative TTL, for SOA records in authority section */
time_t MAX_NEG_TTL = 3600; /* one hour */ time_t MAX_NEG_TTL = 3600; /* one hour */
/** MIN Negative TTL, for SOA records in authority section */
time_t MIN_NEG_TTL = 0;
/** If we serve expired entries and prefetch them */ /** If we serve expired entries and prefetch them */
int SERVE_EXPIRED = 0; int SERVE_EXPIRED = 0;
/** Time to serve records after expiration */ /** Time to serve records after expiration */
@ -223,18 +225,25 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
/* negative response. see if TTL of SOA record larger than the /* negative response. see if TTL of SOA record larger than the
* minimum-ttl in the rdata of the SOA record */ * minimum-ttl in the rdata of the SOA record */
if(*rr_ttl > soa_find_minttl(rr)) if(*rr_ttl > soa_find_minttl(rr)) *rr_ttl = soa_find_minttl(rr);
*rr_ttl = soa_find_minttl(rr); if(!SERVE_ORIGINAL_TTL) {
} /* If MIN_NEG_TTL is configured skip setting MIN_TTL */
if(!SERVE_ORIGINAL_TTL && (*rr_ttl < MIN_TTL)) if(MIN_NEG_TTL <= 0 && *rr_ttl < MIN_TTL) {
*rr_ttl = MIN_TTL; *rr_ttl = MIN_TTL;
if(!SERVE_ORIGINAL_TTL && (*rr_ttl > MAX_TTL)) }
*rr_ttl = MAX_TTL; if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL;
if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { }
/* max neg ttl overrides the min and max ttl of everything /* MAX_NEG_TTL overrides the min and max ttl of everything
* else, it is for a more specific record */ * else; it is for a more specific record */
if(*rr_ttl > MAX_NEG_TTL) if(*rr_ttl > MAX_NEG_TTL) *rr_ttl = MAX_NEG_TTL;
*rr_ttl = MAX_NEG_TTL; /* MIN_NEG_TTL overrides the min and max ttl of everything
* else if configured; it is for a more specific record */
if(MIN_NEG_TTL > 0 && *rr_ttl < MIN_NEG_TTL) {
*rr_ttl = MIN_NEG_TTL;
}
} else if(!SERVE_ORIGINAL_TTL) {
if(*rr_ttl < MIN_TTL) *rr_ttl = MIN_TTL;
if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL;
} }
if(*rr_ttl < data->ttl) if(*rr_ttl < data->ttl)
data->ttl = *rr_ttl; data->ttl = *rr_ttl;

View file

@ -129,7 +129,7 @@ void errinf_origin(struct module_qstate* qstate, struct sock_list *origin)
} }
} }
char* errinf_to_str_bogus(struct module_qstate* qstate) char* errinf_to_str_bogus(struct module_qstate* qstate, struct regional* region)
{ {
char buf[20480]; char buf[20480];
char* p = buf; char* p = buf;
@ -148,7 +148,10 @@ char* errinf_to_str_bogus(struct module_qstate* qstate)
snprintf(p, left, " %s", s->str); snprintf(p, left, " %s", s->str);
left -= strlen(p); p += strlen(p); left -= strlen(p); p += strlen(p);
} }
p = strdup(buf); if(region)
p = regional_strdup(region, buf);
else
p = strdup(buf);
if(!p) if(!p)
log_err("malloc failure in errinf_to_str"); log_err("malloc failure in errinf_to_str");
return p; return p;
@ -188,7 +191,7 @@ char* errinf_to_str_servfail(struct module_qstate* qstate)
snprintf(p, left, " %s", s->str); snprintf(p, left, " %s", s->str);
left -= strlen(p); p += strlen(p); left -= strlen(p); p += strlen(p);
} }
p = strdup(buf); p = regional_strdup(qstate->region, buf);
if(!p) if(!p)
log_err("malloc failure in errinf_to_str"); log_err("malloc failure in errinf_to_str");
return p; return p;
@ -206,7 +209,7 @@ char* errinf_to_str_misc(struct module_qstate* qstate)
snprintf(p, left, "%s%s", (s==qstate->errinf?"":" "), s->str); snprintf(p, left, "%s%s", (s==qstate->errinf?"":" "), s->str);
left -= strlen(p); p += strlen(p); left -= strlen(p); p += strlen(p);
} }
p = strdup(buf); p = regional_strdup(qstate->region, buf);
if(!p) if(!p)
log_err("malloc failure in errinf_to_str"); log_err("malloc failure in errinf_to_str");
return p; return p;

View file

@ -180,6 +180,7 @@ struct iter_hints;
struct respip_set; struct respip_set;
struct respip_client_info; struct respip_client_info;
struct respip_addr_info; struct respip_addr_info;
struct module_stack;
/** Maximum number of modules in operation */ /** Maximum number of modules in operation */
#define MAX_MODULE 16 #define MAX_MODULE 16
@ -511,10 +512,10 @@ struct module_env {
/** auth zones */ /** auth zones */
struct auth_zones* auth_zones; struct auth_zones* auth_zones;
/** Mapping of forwarding zones to targets. /** Mapping of forwarding zones to targets.
* iterator forwarder information. per-thread, created by worker */ * iterator forwarder information. */
struct iter_forwards* fwds; struct iter_forwards* fwds;
/** /**
* iterator forwarder information. per-thread, created by worker. * iterator stub information.
* The hints -- these aren't stored in the cache because they don't * The hints -- these aren't stored in the cache because they don't
* expire. The hints are always used to "prime" the cache. Note * expire. The hints are always used to "prime" the cache. Note
* that both root hints and stub zone "hints" are stored in this * that both root hints and stub zone "hints" are stored in this
@ -537,6 +538,12 @@ struct module_env {
/** EDNS client string information */ /** EDNS client string information */
struct edns_strings* edns_strings; struct edns_strings* edns_strings;
/** module stack */
struct module_stack* modstack;
#ifdef USE_CACHEDB
/** the cachedb enabled value, copied and stored here. */
int cachedb_enabled;
#endif
/* Make every mesh state unique, do not aggregate mesh states. */ /* Make every mesh state unique, do not aggregate mesh states. */
int unique_mesh; int unique_mesh;
}; };
@ -824,10 +831,11 @@ void errinf_dname(struct module_qstate* qstate, const char* str,
/** /**
* Create error info in string. For validation failures. * Create error info in string. For validation failures.
* @param qstate: query state. * @param qstate: query state.
* @param region: the region for the result or NULL for malloced result.
* @return string or NULL on malloc failure (already logged). * @return string or NULL on malloc failure (already logged).
* This string is malloced and has to be freed by caller. * This string is malloced if region is NULL and has to be freed by caller.
*/ */
char* errinf_to_str_bogus(struct module_qstate* qstate); char* errinf_to_str_bogus(struct module_qstate* qstate, struct regional* region);
/** /**
* Check the sldns_ede_code of the qstate->errinf. * Check the sldns_ede_code of the qstate->errinf.
@ -840,7 +848,6 @@ sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate);
* Create error info in string. For other servfails. * Create error info in string. For other servfails.
* @param qstate: query state. * @param qstate: query state.
* @return string or NULL on malloc failure (already logged). * @return string or NULL on malloc failure (already logged).
* This string is malloced and has to be freed by caller.
*/ */
char* errinf_to_str_servfail(struct module_qstate* qstate); char* errinf_to_str_servfail(struct module_qstate* qstate);
@ -848,7 +855,6 @@ char* errinf_to_str_servfail(struct module_qstate* qstate);
* Create error info in string. For misc failures that are not servfail. * Create error info in string. For misc failures that are not servfail.
* @param qstate: query state. * @param qstate: query state.
* @return string or NULL on malloc failure (already logged). * @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); char* errinf_to_str_misc(struct module_qstate* qstate);

View file

@ -77,6 +77,8 @@
/** max length of an IP address (the address portion) that we allow */ /** max length of an IP address (the address portion) that we allow */
#define MAX_ADDR_STRLEN 128 /* characters */ #define MAX_ADDR_STRLEN 128 /* characters */
/** max length of a hostname (with port and tls name) that we allow */
#define MAX_HOST_STRLEN (LDNS_MAX_DOMAINLEN * 3) /* characters */
/** default value for EDNS ADVERTISED size */ /** default value for EDNS ADVERTISED size */
uint16_t EDNS_ADVERTISED_SIZE = 4096; uint16_t EDNS_ADVERTISED_SIZE = 4096;
@ -486,28 +488,38 @@ uint8_t* authextstrtodname(char* str, int* port, char** auth_name)
*port = UNBOUND_DNS_PORT; *port = UNBOUND_DNS_PORT;
*auth_name = NULL; *auth_name = NULL;
if((s=strchr(str, '@'))) { if((s=strchr(str, '@'))) {
char buf[MAX_HOST_STRLEN];
size_t len = (size_t)(s-str);
char* hash = strchr(s+1, '#'); char* hash = strchr(s+1, '#');
if(hash) { if(hash) {
*auth_name = hash+1; *auth_name = hash+1;
} else { } else {
*auth_name = NULL; *auth_name = NULL;
} }
if(len >= MAX_HOST_STRLEN) {
return NULL;
}
(void)strlcpy(buf, str, sizeof(buf));
buf[len] = 0;
*port = atoi(s+1); *port = atoi(s+1);
if(*port == 0) { if(*port == 0) {
if(!hash && strcmp(s+1,"0")!=0) if(!hash && strcmp(s+1,"0")!=0)
return 0; return NULL;
if(hash && strncmp(s+1,"0#",2)!=0) if(hash && strncmp(s+1,"0#",2)!=0)
return 0; return NULL;
} }
*s = 0; dname = sldns_str2wire_dname(buf, &dname_len);
dname = sldns_str2wire_dname(str, &dname_len);
*s = '@';
} else if((s=strchr(str, '#'))) { } else if((s=strchr(str, '#'))) {
char buf[MAX_HOST_STRLEN];
size_t len = (size_t)(s-str);
if(len >= MAX_HOST_STRLEN) {
return NULL;
}
(void)strlcpy(buf, str, sizeof(buf));
buf[len] = 0;
*port = UNBOUND_DNS_OVER_TLS_PORT; *port = UNBOUND_DNS_OVER_TLS_PORT;
*auth_name = s+1; *auth_name = s+1;
*s = 0; dname = sldns_str2wire_dname(buf, &dname_len);
dname = sldns_str2wire_dname(str, &dname_len);
*s = '#';
} else { } else {
dname = sldns_str2wire_dname(str, &dname_len); dname = sldns_str2wire_dname(str, &dname_len);
} }
@ -1026,11 +1038,11 @@ static void log_crypto_err_io_code_arg(const char* str, int r,
} else { } else {
if(print_errno) { if(print_errno) {
if(errno == 0) if(errno == 0)
log_err("str: syscall error with errno %s", log_err("%s: syscall error with errno %s",
strerror(errno)); str, strerror(errno));
else log_err("str: %s", strerror(errno)); else log_err("%s: %s", str, strerror(errno));
} else { } else {
log_err("str: %s", inf); log_err("%s: %s", str, inf);
} }
} }
} }

View file

@ -4772,9 +4772,9 @@ comm_point_send_reply(struct comm_reply *repinfo)
* sending src (client)/dst (local service) addresses over DNSTAP from udp callback * sending src (client)/dst (local service) addresses over DNSTAP from udp callback
*/ */
if(repinfo->c->dtenv != NULL && repinfo->c->dtenv->log_client_response_messages) { if(repinfo->c->dtenv != NULL && repinfo->c->dtenv->log_client_response_messages) {
log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen); log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen);
log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen); log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
dt_msg_send_client_response(repinfo->c->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type, repinfo->c->ssl, repinfo->c->buffer); dt_msg_send_client_response(repinfo->c->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, repinfo->c->type, repinfo->c->ssl, repinfo->c->buffer);
} }
#endif #endif
} else { } else {
@ -4783,9 +4783,9 @@ comm_point_send_reply(struct comm_reply *repinfo)
* sending src (client)/dst (local service) addresses over DNSTAP from TCP callback * sending src (client)/dst (local service) addresses over DNSTAP from TCP callback
*/ */
if(repinfo->c->tcp_parent->dtenv != NULL && repinfo->c->tcp_parent->dtenv->log_client_response_messages) { if(repinfo->c->tcp_parent->dtenv != NULL && repinfo->c->tcp_parent->dtenv->log_client_response_messages) {
log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen); log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen);
log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen); log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type, repinfo->c->ssl, dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, repinfo->c->type, repinfo->c->ssl,
( repinfo->c->tcp_req_info? repinfo->c->tcp_req_info->spool_buffer: repinfo->c->buffer )); ( repinfo->c->tcp_req_info? repinfo->c->tcp_req_info->spool_buffer: repinfo->c->buffer ));
} }
#endif #endif

View file

@ -181,6 +181,8 @@ struct comm_point {
/** if the event is added or not */ /** if the event is added or not */
int event_added; int event_added;
/** Reference to struct that is part of the listening ports,
* where for listening ports information is kept about the address. */
struct unbound_socket* socket; struct unbound_socket* socket;
/** file descriptor for communication point */ /** file descriptor for communication point */

View file

@ -89,7 +89,7 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
# if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ # if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
__BYTE_ORDER == __LITTLE_ENDIAN) || \ __BYTE_ORDER == __LITTLE_ENDIAN) || \
(defined(i386) || defined(__i386__) || defined(__i486__) || \ (defined(i386) || defined(__i386__) || defined(__i486__) || \
defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL) || defined(__x86)) defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL) || defined(__x86) || defined(__loongarch__))
# define HASH_LITTLE_ENDIAN 1 # define HASH_LITTLE_ENDIAN 1
# define HASH_BIG_ENDIAN 0 # define HASH_BIG_ENDIAN 0
# elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ # elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \

View file

@ -528,6 +528,40 @@ lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md)
lock_quick_unlock(&table->lock); lock_quick_unlock(&table->lock);
} }
void
lruhash_update_space_used(struct lruhash* table, void* cb_arg, int diff_size)
{
struct lruhash_entry *reclaimlist = NULL;
fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
if(cb_arg == NULL) cb_arg = table->cb_arg;
/* update space used */
lock_quick_lock(&table->lock);
if((int)table->space_used + diff_size < 0)
table->space_used = 0;
else table->space_used = (size_t)((int)table->space_used + diff_size);
if(table->space_used > table->space_max)
reclaim_space(table, &reclaimlist);
lock_quick_unlock(&table->lock);
/* finish reclaim if any (outside of critical region) */
while(reclaimlist) {
struct lruhash_entry* n = reclaimlist->overflow_next;
void* d = reclaimlist->data;
(*table->delkeyfunc)(reclaimlist->key, cb_arg);
(*table->deldatafunc)(d, cb_arg);
reclaimlist = n;
}
}
void void
lruhash_traverse(struct lruhash* h, int wr, lruhash_traverse(struct lruhash* h, int wr,
void (*func)(struct lruhash_entry*, void*), void* arg) void (*func)(struct lruhash_entry*, void*), void* arg)

View file

@ -303,6 +303,17 @@ void lru_touch(struct lruhash* table, struct lruhash_entry* entry);
*/ */
void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md); void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md);
/**
* Update the size of an element in the hashtable.
*
* @param table: hash table.
* @param cb_override: if not NULL overrides the cb_arg for deletefunc.
* @param diff_size: difference in size to the hash table storage.
* This is newsize - oldsize, a positive number uses more space.
*/
void lruhash_update_space_used(struct lruhash* table, void* cb_override,
int diff_size);
/************************* getdns functions ************************/ /************************* getdns functions ************************/
/*** these are used by getdns only and not by unbound. ***/ /*** these are used by getdns only and not by unbound. ***/

View file

@ -166,6 +166,13 @@ int slabhash_is_size(struct slabhash* sl, size_t size, size_t slabs)
return 0; return 0;
} }
void slabhash_update_space_used(struct slabhash* sl, hashvalue_type hash,
void* cb_arg, int diff_size)
{
lruhash_update_space_used(sl->array[slab_idx(sl, hash)], cb_arg,
diff_size);
}
size_t slabhash_get_mem(struct slabhash* sl) size_t slabhash_get_mem(struct slabhash* sl)
{ {
size_t i, total = sizeof(*sl); size_t i, total = sizeof(*sl);

View file

@ -161,6 +161,18 @@ size_t slabhash_get_size(struct slabhash* table);
*/ */
int slabhash_is_size(struct slabhash* table, size_t size, size_t slabs); int slabhash_is_size(struct slabhash* table, size_t size, size_t slabs);
/**
* Update the size of an element in the hashtable, uses
* lruhash_update_space_used.
*
* @param table: hash table.
* @param hash: hash value. User calculates the hash.
* @param cb_override: if not NULL overrides the cb_arg for deletefunc.
* @param diff_size: difference in size to the hash table storage.
*/
void slabhash_update_space_used(struct slabhash* table, hashvalue_type hash,
void* cb_override, int diff_size);
/** /**
* Retrieve slab hash current memory use. * Retrieve slab hash current memory use.
* @param table: hash table. * @param table: hash table.

View file

@ -119,6 +119,29 @@ val_classify_response(uint16_t query_flags, struct query_info* origqinf,
if(rcode == LDNS_RCODE_NOERROR && qinf->qtype == LDNS_RR_TYPE_ANY) if(rcode == LDNS_RCODE_NOERROR && qinf->qtype == LDNS_RR_TYPE_ANY)
return VAL_CLASS_ANY; return VAL_CLASS_ANY;
/* For the query type DNAME, the name matters. Equal name is the
* answer looked for, but a subdomain redirects the query. */
if(qinf->qtype == LDNS_RR_TYPE_DNAME) {
for(i=skip; i<rep->an_numrrsets; i++) {
if(rcode == LDNS_RCODE_NOERROR &&
ntohs(rep->rrsets[i]->rk.type)
== LDNS_RR_TYPE_DNAME &&
query_dname_compare(qinf->qname,
rep->rrsets[i]->rk.dname) == 0) {
/* type is DNAME and name is equal, it is
* the answer. For the query name a subdomain
* of the rrset.dname it would redirect. */
return VAL_CLASS_POSITIVE;
}
if(ntohs(rep->rrsets[i]->rk.type)
== LDNS_RR_TYPE_CNAME)
return VAL_CLASS_CNAME;
}
log_dns_msg("validator: error. failed to classify response message: ",
qinf, rep);
return VAL_CLASS_UNKNOWN;
}
/* Note that DNAMEs will be ignored here, unless qtype=DNAME. Unless /* Note that DNAMEs will be ignored here, unless qtype=DNAME. Unless
* qtype=CNAME, this will yield a CNAME response. */ * qtype=CNAME, this will yield a CNAME response. */
for(i=skip; i<rep->an_numrrsets; i++) { for(i=skip; i<rep->an_numrrsets; i++) {
@ -231,6 +254,21 @@ val_find_signer(enum val_classification subtype, struct query_info* qinf,
rep->rrsets[i]->rk.dname) == 0) { rep->rrsets[i]->rk.dname) == 0) {
val_find_rrset_signer(rep->rrsets[i], val_find_rrset_signer(rep->rrsets[i],
signer_name, signer_len); signer_name, signer_len);
/* If there was no signer, and the query
* was for type CNAME, and this is a CNAME,
* and the previous is a DNAME, then this
* is the synthesized CNAME, use the signer
* of the DNAME record. */
if(*signer_name == NULL &&
qinf->qtype == LDNS_RR_TYPE_CNAME &&
ntohs(rep->rrsets[i]->rk.type) ==
LDNS_RR_TYPE_CNAME && i > skip &&
ntohs(rep->rrsets[i-1]->rk.type) ==
LDNS_RR_TYPE_DNAME &&
dname_strict_subdomain_c(rep->rrsets[i]->rk.dname, rep->rrsets[i-1]->rk.dname)) {
val_find_rrset_signer(rep->rrsets[i-1],
signer_name, signer_len);
}
return; return;
} }
} }

View file

@ -117,7 +117,7 @@ fill_nsec3_iter(struct val_env* ve, char* s, int c)
s = e; s = e;
if(i>0 && ve->nsec3_keysize[i-1] >= ve->nsec3_keysize[i]) { if(i>0 && ve->nsec3_keysize[i-1] >= ve->nsec3_keysize[i]) {
log_err("nsec3 key iterations not ascending: %d %d", log_err("nsec3 key iterations not ascending: %d %d",
(int)ve->nsec3_keysize[i-1], (int)ve->nsec3_keysize[i-1],
(int)ve->nsec3_keysize[i]); (int)ve->nsec3_keysize[i]);
return 0; return 0;
} }
@ -621,7 +621,6 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
* @param vq: validator query state. * @param vq: validator query state.
* @param env: module env for verify. * @param env: module env for verify.
* @param ve: validator env for verify. * @param ve: validator env for verify.
* @param qchase: query that was made.
* @param chase_reply: answer to validate. * @param chase_reply: answer to validate.
* @param key_entry: the key entry, which is trusted, and which matches * @param key_entry: the key entry, which is trusted, and which matches
* the signer of the answer. The key entry isgood(). * the signer of the answer. The key entry isgood().
@ -632,7 +631,7 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
*/ */
static int static int
validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq, validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
struct module_env* env, struct val_env* ve, struct query_info* qchase, struct module_env* env, struct val_env* ve,
struct reply_info* chase_reply, struct key_entry_key* key_entry, struct reply_info* chase_reply, struct key_entry_key* key_entry,
int* suspend) int* suspend)
{ {
@ -640,7 +639,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
size_t i, slen; size_t i, slen;
struct ub_packed_rrset_key* s; struct ub_packed_rrset_key* s;
enum sec_status sec; enum sec_status sec;
int dname_seen = 0, num_verifies = 0, verified, have_state = 0; int num_verifies = 0, verified, have_state = 0;
char* reason = NULL; char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS; sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
*suspend = 0; *suspend = 0;
@ -658,9 +657,13 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
/* Skip the CNAME following a (validated) DNAME. /* Skip the CNAME following a (validated) DNAME.
* Because of the normalization routines in the iterator, * Because of the normalization routines in the iterator,
* there will always be an unsigned CNAME following a DNAME * there will always be an unsigned CNAME following a DNAME
* (unless qtype=DNAME). */ * (unless qtype=DNAME in the answer part). */
if(dname_seen && ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) { if(i>0 && ntohs(chase_reply->rrsets[i-1]->rk.type) ==
dname_seen = 0; LDNS_RR_TYPE_DNAME &&
ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
((struct packed_rrset_data*)chase_reply->rrsets[i-1]->entry.data)->security == sec_status_secure &&
dname_strict_subdomain_c(s->rk.dname, chase_reply->rrsets[i-1]->rk.dname)
) {
/* CNAME was synthesized by our own iterator */ /* CNAME was synthesized by our own iterator */
/* since the DNAME verified, mark the CNAME as secure */ /* since the DNAME verified, mark the CNAME as secure */
((struct packed_rrset_data*)s->entry.data)->security = ((struct packed_rrset_data*)s->entry.data)->security =
@ -691,12 +694,6 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
return 0; return 0;
} }
/* Notice a DNAME that should be followed by an unsigned
* CNAME. */
if(qchase->qtype != LDNS_RR_TYPE_DNAME &&
ntohs(s->rk.type) == LDNS_RR_TYPE_DNAME) {
dname_seen = 1;
}
num_verifies += verified; num_verifies += verified;
if(num_verifies > MAX_VALIDATE_AT_ONCE && if(num_verifies > MAX_VALIDATE_AT_ONCE &&
i+1 < (env->cfg->val_clean_additional? i+1 < (env->cfg->val_clean_additional?
@ -2186,7 +2183,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq,
/* check signatures in the message; /* check signatures in the message;
* answer and authority must be valid, additional is only checked. */ * answer and authority must be valid, additional is only checked. */
if(!validate_msg_signatures(qstate, vq, qstate->env, ve, &vq->qchase, if(!validate_msg_signatures(qstate, vq, qstate->env, ve,
vq->chase_reply, vq->key_entry, &suspend)) { vq->chase_reply, vq->key_entry, &suspend)) {
if(suspend) { if(suspend) {
if(!validate_suspend_setup_timer(qstate, vq, if(!validate_suspend_setup_timer(qstate, vq,
@ -2456,19 +2453,12 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
log_query_info(NO_VERBOSE, "validation failure", log_query_info(NO_VERBOSE, "validation failure",
&qstate->qinfo); &qstate->qinfo);
else { else {
char* err_str = errinf_to_str_bogus(qstate); char* err_str = errinf_to_str_bogus(qstate,
qstate->region);
if(err_str) { if(err_str) {
size_t err_str_len = strlen(err_str);
log_info("%s", err_str); log_info("%s", err_str);
/* allocate space and store the error vq->orig_msg->rep->reason_bogus_str = err_str;
* string */
vq->orig_msg->rep->reason_bogus_str = regional_alloc(
qstate->region,
sizeof(char) * (err_str_len+1));
memcpy(vq->orig_msg->rep->reason_bogus_str,
err_str, err_str_len+1);
} }
free(err_str);
} }
} }
/* /*

View file

@ -1,4 +1,4 @@
/* $OpenBSD: conf.c,v 1.47 2023/10/26 14:13:37 jsg Exp $ */ /* $OpenBSD: conf.c,v 1.48 2024/06/14 19:49:17 kettenis Exp $ */
/* /*
* Copyright (c) 1996 Michael Shalayeff * Copyright (c) 1996 Michael Shalayeff
@ -47,7 +47,7 @@
#include "efipxe.h" #include "efipxe.h"
#include "softraid_arm64.h" #include "softraid_arm64.h"
const char version[] = "1.18"; const char version[] = "1.19";
int debug = 0; int debug = 0;
struct fs_ops file_system[] = { struct fs_ops file_system[] = {

View file

@ -1,4 +1,4 @@
/* $OpenBSD: efiboot.c,v 1.50 2024/02/23 21:52:12 kettenis Exp $ */ /* $OpenBSD: efiboot.c,v 1.51 2024/06/14 19:49:17 kettenis Exp $ */
/* /*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@ -41,6 +41,7 @@
#include "efidev.h" #include "efidev.h"
#include "efiboot.h" #include "efiboot.h"
#include "efidt.h"
#include "fdt.h" #include "fdt.h"
EFI_SYSTEM_TABLE *ST; EFI_SYSTEM_TABLE *ST;
@ -67,6 +68,7 @@ static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GUID fdt_guid = FDT_TABLE_GUID; static EFI_GUID fdt_guid = FDT_TABLE_GUID;
static EFI_GUID smbios_guid = SMBIOS_TABLE_GUID; static EFI_GUID smbios_guid = SMBIOS_TABLE_GUID;
static EFI_GUID smbios3_guid = SMBIOS3_TABLE_GUID; static EFI_GUID smbios3_guid = SMBIOS3_TABLE_GUID;
static EFI_GUID dt_fixup_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
#define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID)) #define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID))
@ -1134,12 +1136,18 @@ efi_fdt(void)
return fdt_override ? fdt_override : fdt_sys; return fdt_override ? fdt_override : fdt_sys;
} }
#define EXTRA_DT_SPACE (32 * 1024)
int int
fdt_load_override(char *file) fdt_load_override(char *file)
{ {
EFI_DT_FIXUP_PROTOCOL *dt_fixup;
EFI_PHYSICAL_ADDRESS addr; EFI_PHYSICAL_ADDRESS addr;
char path[MAXPATHLEN]; char path[MAXPATHLEN];
EFI_STATUS status;
struct stat sb; struct stat sb;
size_t dt_size;
UINTN sz;
int fd; int fd;
if (file == NULL && fdt_override) { if (file == NULL && fdt_override) {
@ -1157,7 +1165,8 @@ fdt_load_override(char *file)
printf("cannot open %s\n", path); printf("cannot open %s\n", path);
return 0; return 0;
} }
if (efi_memprobe_find(EFI_SIZE_TO_PAGES(sb.st_size), dt_size = sb.st_size + EXTRA_DT_SPACE;
if (efi_memprobe_find(EFI_SIZE_TO_PAGES(dt_size),
PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) { PAGE_SIZE, EfiLoaderData, &addr) != EFI_SUCCESS) {
printf("cannot allocate memory for %s\n", path); printf("cannot allocate memory for %s\n", path);
return 0; return 0;
@ -1167,9 +1176,18 @@ fdt_load_override(char *file)
return 0; return 0;
} }
status = BS->LocateProtocol(&dt_fixup_guid, NULL, (void **)&dt_fixup);
if (status == EFI_SUCCESS) {
sz = dt_size;
status = dt_fixup->Fixup(dt_fixup, (void *)addr, &sz,
EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
if (status != EFI_SUCCESS)
panic("DT fixup failed: 0x%lx", status);
}
if (!fdt_init((void *)addr)) { if (!fdt_init((void *)addr)) {
printf("invalid device tree\n"); printf("invalid device tree\n");
BS->FreePages(addr, EFI_SIZE_TO_PAGES(sb.st_size)); BS->FreePages(addr, EFI_SIZE_TO_PAGES(dt_size));
return 0; return 0;
} }
@ -1180,7 +1198,7 @@ fdt_load_override(char *file)
} }
fdt_override = (void *)addr; fdt_override = (void *)addr;
fdt_override_size = sb.st_size; fdt_override_size = dt_size;
return 0; return 0;
} }

View file

@ -0,0 +1,44 @@
/* $OpenBSD: efidt.h,v 1.1 2024/06/14 19:49:17 kettenis Exp $ */
/*
* Copyright (c) 2024 Mark Kettenis <kettenis@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <efi.h>
#include <efiapi.h>
#define EFI_DT_FIXUP_PROTOCOL_GUID \
{ 0xe617d64c, 0xfe08, 0x46da, \
{ 0xf4, 0xdc, 0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00 } }
INTERFACE_DECL(_EFI_DT_FIXUP_PROTOCOL);
typedef EFI_STATUS
(EFIAPI *EFI_DT_FIXUP) (
IN struct _EFI_DT_FIXUP_PROTOCOL *This,
IN VOID *Fdt,
IN OUT UINTN *BufferSize,
IN UINT32 Flags
);
#define EFI_DT_APPLY_FIXUPS 0x00000001
#define EFI_DT_RESERVE_MEMORY 0x00000002
typedef struct _EFI_DT_FIXUP_PROTOCOL {
UINT64 Revision;
EFI_DT_FIXUP Fixup;
} EFI_DT_FIXUP_PROTOCOL;

View file

@ -1,4 +1,4 @@
/* $OpenBSD: ufshci.c,v 1.35 2024/06/09 03:21:54 jsg Exp $ */ /* $OpenBSD: ufshci.c,v 1.37 2024/06/14 20:52:07 mglocker Exp $ */
/* /*
* Copyright (c) 2022 Marcus Glocker <mglocker@openbsd.org> * Copyright (c) 2022 Marcus Glocker <mglocker@openbsd.org>
@ -68,7 +68,7 @@ void ufshci_dmamem_free(struct ufshci_softc *,
struct ufshci_dmamem *); struct ufshci_dmamem *);
int ufshci_alloc(struct ufshci_softc *); int ufshci_alloc(struct ufshci_softc *);
int ufshci_init(struct ufshci_softc *); int ufshci_init(struct ufshci_softc *);
int ufshci_disable(struct ufshci_softc *); void ufshci_disable(struct ufshci_softc *);
int ufshci_doorbell_read(struct ufshci_softc *); int ufshci_doorbell_read(struct ufshci_softc *);
void ufshci_doorbell_write(struct ufshci_softc *, int); void ufshci_doorbell_write(struct ufshci_softc *, int);
int ufshci_doorbell_poll(struct ufshci_softc *, int, int ufshci_doorbell_poll(struct ufshci_softc *, int,
@ -88,7 +88,7 @@ int ufshci_utr_cmd_io(struct ufshci_softc *,
int ufshci_utr_cmd_sync(struct ufshci_softc *, int ufshci_utr_cmd_sync(struct ufshci_softc *,
struct ufshci_ccb *, struct scsi_xfer *, struct ufshci_ccb *, struct scsi_xfer *,
uint32_t, uint16_t); uint32_t, uint16_t);
int ufshci_xfer_complete(struct ufshci_softc *); void ufshci_xfer_complete(struct ufshci_softc *);
/* SCSI */ /* SCSI */
int ufshci_ccb_alloc(struct ufshci_softc *, int); int ufshci_ccb_alloc(struct ufshci_softc *, int);
@ -131,7 +131,7 @@ ufshci_intr(void *arg)
DPRINTF(3, "%s: status=0x%08x\n", __func__, status); DPRINTF(3, "%s: status=0x%08x\n", __func__, status);
if (status == 0) if (status == 0)
return 0; return handled;
if (status & UFSHCI_REG_IS_UCCS) { if (status & UFSHCI_REG_IS_UCCS) {
DPRINTF(3, "%s: UCCS interrupt\n", __func__); DPRINTF(3, "%s: UCCS interrupt\n", __func__);
@ -149,11 +149,13 @@ ufshci_intr(void *arg)
hcs = UFSHCI_READ_4(sc, UFSHCI_REG_HCS); hcs = UFSHCI_READ_4(sc, UFSHCI_REG_HCS);
printf("%s: Auto-Hibernate enter error UPMCRS=0x%x\n", printf("%s: Auto-Hibernate enter error UPMCRS=0x%x\n",
__func__, UFSHCI_REG_HCS_UPMCRS(hcs)); __func__, UFSHCI_REG_HCS_UPMCRS(hcs));
handled = 1;
} }
if (status & UFSHCI_REG_IS_UHXS) { if (status & UFSHCI_REG_IS_UHXS) {
hcs = UFSHCI_READ_4(sc, UFSHCI_REG_HCS); hcs = UFSHCI_READ_4(sc, UFSHCI_REG_HCS);
printf("%s: Auto-Hibernate exit error UPMCRS=0x%x\n", printf("%s: Auto-Hibernate exit error UPMCRS=0x%x\n",
__func__, UFSHCI_REG_HCS_UPMCRS(hcs)); __func__, UFSHCI_REG_HCS_UPMCRS(hcs));
handled = 1;
} }
if (handled == 0) { if (handled == 0) {
@ -164,7 +166,7 @@ ufshci_intr(void *arg)
/* ACK interrupt */ /* ACK interrupt */
UFSHCI_WRITE_4(sc, UFSHCI_REG_IS, status); UFSHCI_WRITE_4(sc, UFSHCI_REG_IS, status);
return 1; return handled;
} }
int int
@ -177,7 +179,8 @@ ufshci_attach(struct ufshci_softc *sc)
SIMPLEQ_INIT(&sc->sc_ccb_list); SIMPLEQ_INIT(&sc->sc_ccb_list);
scsi_iopool_init(&sc->sc_iopool, sc, ufshci_ccb_get, ufshci_ccb_put); scsi_iopool_init(&sc->sc_iopool, sc, ufshci_ccb_get, ufshci_ccb_put);
ufshci_reset(sc); if (ufshci_reset(sc))
return 1;
sc->sc_ver = UFSHCI_READ_4(sc, UFSHCI_REG_VER); sc->sc_ver = UFSHCI_READ_4(sc, UFSHCI_REG_VER);
printf(", UFSHCI %d.%d%d\n", printf(", UFSHCI %d.%d%d\n",
@ -240,8 +243,10 @@ ufshci_attach(struct ufshci_softc *sc)
sc->sc_flags |= UFSHCI_FLAGS_AGGR_INTR; /* Enable intr. aggregation */ sc->sc_flags |= UFSHCI_FLAGS_AGGR_INTR; /* Enable intr. aggregation */
#endif #endif
/* Allocate the DMA buffers and initialize the controller. */ /* Allocate the DMA buffers and initialize the controller. */
ufshci_alloc(sc); if (ufshci_alloc(sc))
ufshci_init(sc); return 1;
if (ufshci_init(sc))
return 1;
if (ufshci_ccb_alloc(sc, sc->sc_nutrs) != 0) { if (ufshci_ccb_alloc(sc, sc->sc_nutrs) != 0) {
printf("%s: %s: Can't allocate CCBs\n", printf("%s: %s: Can't allocate CCBs\n",
@ -294,7 +299,7 @@ ufshci_reset(struct ufshci_softc *sc)
if (i == retry) { if (i == retry) {
printf("%s: Enabling Host Controller failed!\n", printf("%s: Enabling Host Controller failed!\n",
sc->sc_dev.dv_xname); sc->sc_dev.dv_xname);
return -1; return 1;
} }
DPRINTF(2, "\n%s: Host Controller enabled (i=%d)\n", __func__, i); DPRINTF(2, "\n%s: Host Controller enabled (i=%d)\n", __func__, i);
@ -318,7 +323,7 @@ ufshci_is_poll(struct ufshci_softc *sc, uint32_t type)
} }
if (i == retry) { if (i == retry) {
printf("%s: %s: timeout\n", sc->sc_dev.dv_xname, __func__); printf("%s: %s: timeout\n", sc->sc_dev.dv_xname, __func__);
return -1; return 1;
} }
DPRINTF(3, "%s: completed after %d retries\n", __func__, i); DPRINTF(3, "%s: completed after %d retries\n", __func__, i);
@ -394,7 +399,7 @@ ufshci_alloc(struct ufshci_softc *sc)
if (sc->sc_dmamem_utmrd == NULL) { if (sc->sc_dmamem_utmrd == NULL) {
printf("%s: Can't allocate DMA memory for UTMRD\n", printf("%s: Can't allocate DMA memory for UTMRD\n",
sc->sc_dev.dv_xname); sc->sc_dev.dv_xname);
return -1; return 1;
} }
/* 7.1.1 Host Controller Initialization: 15) */ /* 7.1.1 Host Controller Initialization: 15) */
@ -403,7 +408,7 @@ ufshci_alloc(struct ufshci_softc *sc)
if (sc->sc_dmamem_utrd == NULL) { if (sc->sc_dmamem_utrd == NULL) {
printf("%s: Can't allocate DMA memory for UTRD\n", printf("%s: Can't allocate DMA memory for UTRD\n",
sc->sc_dev.dv_xname); sc->sc_dev.dv_xname);
return -1; return 1;
} }
/* Allocate UCDs. */ /* Allocate UCDs. */
@ -412,7 +417,7 @@ ufshci_alloc(struct ufshci_softc *sc)
if (sc->sc_dmamem_ucd == NULL) { if (sc->sc_dmamem_ucd == NULL) {
printf("%s: Can't allocate DMA memory for UCD\n", printf("%s: Can't allocate DMA memory for UCD\n",
sc->sc_dev.dv_xname); sc->sc_dev.dv_xname);
return -1; return 1;
} }
return 0; return 0;
@ -442,8 +447,8 @@ ufshci_init(struct ufshci_softc *sc)
/* 7.1.1 Host Controller Initialization: 6) */ /* 7.1.1 Host Controller Initialization: 6) */
UFSHCI_WRITE_4(sc, UFSHCI_REG_UICCMD, UFSHCI_WRITE_4(sc, UFSHCI_REG_UICCMD,
UFSHCI_REG_UICCMD_CMDOP_DME_LINKSTARTUP); UFSHCI_REG_UICCMD_CMDOP_DME_LINKSTARTUP);
if (ufshci_is_poll(sc, UFSHCI_REG_IS_UCCS) != 0) if (ufshci_is_poll(sc, UFSHCI_REG_IS_UCCS))
return -1; return 1;
/* /*
* 7.1.1 Host Controller Initialization: 7), 8), 9) * 7.1.1 Host Controller Initialization: 7), 8), 9)
@ -503,7 +508,7 @@ ufshci_init(struct ufshci_softc *sc)
return 0; return 0;
} }
int void
ufshci_disable(struct ufshci_softc *sc) ufshci_disable(struct ufshci_softc *sc)
{ {
/* Stop run queues. */ /* Stop run queues. */
@ -512,8 +517,6 @@ ufshci_disable(struct ufshci_softc *sc)
/* Disable interrupts. */ /* Disable interrupts. */
UFSHCI_WRITE_4(sc, UFSHCI_REG_IE, 0); UFSHCI_WRITE_4(sc, UFSHCI_REG_IE, 0);
return 0;
} }
int int
@ -553,7 +556,7 @@ ufshci_doorbell_poll(struct ufshci_softc *sc, int slot, uint32_t timeout_ms)
} }
if (timeout_us == 0) { if (timeout_us == 0) {
printf("%s: %s: timeout\n", sc->sc_dev.dv_xname, __func__); printf("%s: %s: timeout\n", sc->sc_dev.dv_xname, __func__);
return -1; return 1;
} }
return 0; return 0;
@ -636,7 +639,7 @@ ufshci_utr_cmd_nop(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) { if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
printf("%s: %s: UTRLRSR not set\n", printf("%s: %s: UTRLRSR not set\n",
sc->sc_dev.dv_xname, __func__); sc->sc_dev.dv_xname, __func__);
return -1; return 1;
} }
bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd), bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
@ -746,7 +749,7 @@ ufshci_utr_cmd_lun(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) { if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
printf("%s: %s: UTRLRSR not set\n", printf("%s: %s: UTRLRSR not set\n",
sc->sc_dev.dv_xname, __func__); sc->sc_dev.dv_xname, __func__);
return -1; return 1;
} }
bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd), bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
@ -854,7 +857,7 @@ ufshci_utr_cmd_inquiry(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) { if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
printf("%s: %s: UTRLRSR not set\n", printf("%s: %s: UTRLRSR not set\n",
sc->sc_dev.dv_xname, __func__); sc->sc_dev.dv_xname, __func__);
return -1; return 1;
} }
bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd), bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
@ -866,7 +869,7 @@ ufshci_utr_cmd_inquiry(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
ccb->ccb_status = CCB_STATUS_INPROGRESS; ccb->ccb_status = CCB_STATUS_INPROGRESS;
ufshci_doorbell_write(sc, slot); ufshci_doorbell_write(sc, slot);
return slot; return 0;
} }
int int
@ -966,7 +969,7 @@ ufshci_utr_cmd_capacity16(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) { if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
printf("%s: %s: UTRLRSR not set\n", printf("%s: %s: UTRLRSR not set\n",
sc->sc_dev.dv_xname, __func__); sc->sc_dev.dv_xname, __func__);
return -1; return 1;
} }
bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd), bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
@ -978,7 +981,7 @@ ufshci_utr_cmd_capacity16(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
ccb->ccb_status = CCB_STATUS_INPROGRESS; ccb->ccb_status = CCB_STATUS_INPROGRESS;
ufshci_doorbell_write(sc, slot); ufshci_doorbell_write(sc, slot);
return slot; return 0;
} }
int int
@ -1077,7 +1080,7 @@ ufshci_utr_cmd_capacity(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) { if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
printf("%s: %s: UTRLRSR not set\n", printf("%s: %s: UTRLRSR not set\n",
sc->sc_dev.dv_xname, __func__); sc->sc_dev.dv_xname, __func__);
return -1; return 1;
} }
bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd), bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
@ -1089,7 +1092,7 @@ ufshci_utr_cmd_capacity(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
ccb->ccb_status = CCB_STATUS_INPROGRESS; ccb->ccb_status = CCB_STATUS_INPROGRESS;
ufshci_doorbell_write(sc, slot); ufshci_doorbell_write(sc, slot);
return slot; return 0;
} }
int int
@ -1200,7 +1203,7 @@ ufshci_utr_cmd_io(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) { if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
printf("%s: %s: UTRLRSR not set\n", printf("%s: %s: UTRLRSR not set\n",
sc->sc_dev.dv_xname, __func__); sc->sc_dev.dv_xname, __func__);
return -1; return 1;
} }
bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd), bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
@ -1212,7 +1215,7 @@ ufshci_utr_cmd_io(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
ccb->ccb_status = CCB_STATUS_INPROGRESS; ccb->ccb_status = CCB_STATUS_INPROGRESS;
ufshci_doorbell_write(sc, slot); ufshci_doorbell_write(sc, slot);
return slot; return 0;
} }
int int
@ -1302,7 +1305,7 @@ ufshci_utr_cmd_sync(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) { if (UFSHCI_READ_4(sc, UFSHCI_REG_UTRLRSR) != 1) {
printf("%s: %s: UTRLRSR not set\n", printf("%s: %s: UTRLRSR not set\n",
sc->sc_dev.dv_xname, __func__); sc->sc_dev.dv_xname, __func__);
return -1; return 1;
} }
bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd), bus_dmamap_sync(sc->sc_dmat, UFSHCI_DMA_MAP(sc->sc_dmamem_utrd),
@ -1314,10 +1317,10 @@ ufshci_utr_cmd_sync(struct ufshci_softc *sc, struct ufshci_ccb *ccb,
ccb->ccb_status = CCB_STATUS_INPROGRESS; ccb->ccb_status = CCB_STATUS_INPROGRESS;
ufshci_doorbell_write(sc, slot); ufshci_doorbell_write(sc, slot);
return slot; return 0;
} }
int void
ufshci_xfer_complete(struct ufshci_softc *sc) ufshci_xfer_complete(struct ufshci_softc *sc)
{ {
struct ufshci_ccb *ccb; struct ufshci_ccb *ccb;
@ -1374,8 +1377,6 @@ ufshci_xfer_complete(struct ufshci_softc *sc)
if (ccb->ccb_status == CCB_STATUS_READY2FREE) if (ccb->ccb_status == CCB_STATUS_READY2FREE)
ccb->ccb_done(sc, ccb); ccb->ccb_done(sc, ccb);
} }
return 0;
} }
int int
@ -1589,7 +1590,7 @@ ufshci_scsi_inquiry(struct scsi_xfer *xs)
error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL, error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
if (error != 0) { if (error) {
printf("%s: bus_dmamap_load error=%d\n", __func__, error); printf("%s: bus_dmamap_load error=%d\n", __func__, error);
goto error1; goto error1;
} }
@ -1602,7 +1603,7 @@ ufshci_scsi_inquiry(struct scsi_xfer *xs)
/* Response length should be UPIU_SCSI_RSP_INQUIRY_SIZE. */ /* Response length should be UPIU_SCSI_RSP_INQUIRY_SIZE. */
error = ufshci_utr_cmd_inquiry(sc, ccb, xs); error = ufshci_utr_cmd_inquiry(sc, ccb, xs);
if (error == -1) if (error)
goto error2; goto error2;
if (ISSET(xs->flags, SCSI_POLL)) { if (ISSET(xs->flags, SCSI_POLL)) {
@ -1644,7 +1645,7 @@ ufshci_scsi_capacity16(struct scsi_xfer *xs)
error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL, error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
if (error != 0) { if (error) {
printf("%s: bus_dmamap_load error=%d\n", __func__, error); printf("%s: bus_dmamap_load error=%d\n", __func__, error);
goto error1; goto error1;
} }
@ -1657,7 +1658,7 @@ ufshci_scsi_capacity16(struct scsi_xfer *xs)
/* Response length should be UPIU_SCSI_RSP_CAPACITY16_SIZE. */ /* Response length should be UPIU_SCSI_RSP_CAPACITY16_SIZE. */
error = ufshci_utr_cmd_capacity16(sc, ccb, xs); error = ufshci_utr_cmd_capacity16(sc, ccb, xs);
if (error == -1) if (error)
goto error2; goto error2;
if (ISSET(xs->flags, SCSI_POLL)) { if (ISSET(xs->flags, SCSI_POLL)) {
@ -1699,7 +1700,7 @@ ufshci_scsi_capacity(struct scsi_xfer *xs)
error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL, error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
if (error != 0) { if (error) {
printf("%s: bus_dmamap_load error=%d\n", __func__, error); printf("%s: bus_dmamap_load error=%d\n", __func__, error);
goto error1; goto error1;
} }
@ -1712,7 +1713,7 @@ ufshci_scsi_capacity(struct scsi_xfer *xs)
/* Response length should be UPIU_SCSI_RSP_CAPACITY_SIZE */ /* Response length should be UPIU_SCSI_RSP_CAPACITY_SIZE */
error = ufshci_utr_cmd_capacity(sc, ccb, xs); error = ufshci_utr_cmd_capacity(sc, ccb, xs);
if (error == -1) if (error)
goto error2; goto error2;
if (ISSET(xs->flags, SCSI_POLL)) { if (ISSET(xs->flags, SCSI_POLL)) {
@ -1757,7 +1758,7 @@ ufshci_scsi_sync(struct scsi_xfer *xs)
error = ufshci_utr_cmd_sync(sc, ccb, xs, (uint32_t)lba, error = ufshci_utr_cmd_sync(sc, ccb, xs, (uint32_t)lba,
(uint16_t)blocks); (uint16_t)blocks);
if (error == -1) if (error)
goto error; goto error;
if (ISSET(xs->flags, SCSI_POLL)) { if (ISSET(xs->flags, SCSI_POLL)) {
@ -1797,7 +1798,7 @@ ufshci_scsi_io(struct scsi_xfer *xs, int dir)
error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL, error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data, xs->datalen, NULL,
ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); ISSET(xs->flags, SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
if (error != 0) { if (error) {
printf("%s: bus_dmamap_load error=%d\n", __func__, error); printf("%s: bus_dmamap_load error=%d\n", __func__, error);
goto error1; goto error1;
} }
@ -1813,7 +1814,7 @@ ufshci_scsi_io(struct scsi_xfer *xs, int dir)
error = ufshci_utr_cmd_io(sc, ccb, xs, SCSI_DATA_IN); error = ufshci_utr_cmd_io(sc, ccb, xs, SCSI_DATA_IN);
else else
error = ufshci_utr_cmd_io(sc, ccb, xs, SCSI_DATA_OUT); error = ufshci_utr_cmd_io(sc, ccb, xs, SCSI_DATA_OUT);
if (error == -1) if (error)
goto error2; goto error2;
if (ISSET(xs->flags, SCSI_POLL)) { if (ISSET(xs->flags, SCSI_POLL)) {

View file

@ -1,4 +1,4 @@
/* $OpenBSD: ofw_regulator.c,v 1.19 2023/04/15 03:19:43 dlg Exp $ */ /* $OpenBSD: ofw_regulator.c,v 1.20 2024/06/14 20:00:32 kettenis Exp $ */
/* /*
* Copyright (c) 2016 Mark Kettenis * Copyright (c) 2016 Mark Kettenis
* *
@ -56,6 +56,11 @@ regulator_register(struct regulator_device *rd)
rd->rd_ramp_delay = rd->rd_ramp_delay =
OF_getpropint(rd->rd_node, "regulator-ramp-delay", 0); OF_getpropint(rd->rd_node, "regulator-ramp-delay", 0);
rd->rd_coupled =
OF_getpropint(rd->rd_node, "regulator-coupled-with", 0);
rd->rd_max_spread =
OF_getpropint(rd->rd_node, "regulator-coupled-max-spread", 0);
if (rd->rd_get_voltage && rd->rd_set_voltage) { if (rd->rd_get_voltage && rd->rd_set_voltage) {
uint32_t voltage = rd->rd_get_voltage(rd->rd_cookie); uint32_t voltage = rd->rd_get_voltage(rd->rd_cookie);
if (voltage < rd->rd_volt_min) if (voltage < rd->rd_volt_min)
@ -249,6 +254,10 @@ regulator_set_voltage(uint32_t phandle, uint32_t voltage)
if (rd && (voltage < rd->rd_volt_min || voltage > rd->rd_volt_max)) if (rd && (voltage < rd->rd_volt_min || voltage > rd->rd_volt_max))
return EINVAL; return EINVAL;
/* XXX Coupled regulators are unsupported for now. */
if (rd && rd->rd_coupled)
return ENOTSUP;
if (rd && rd->rd_set_voltage) { if (rd && rd->rd_set_voltage) {
regulator_do_notify(rd->rd_phandle, voltage); regulator_do_notify(rd->rd_phandle, voltage);

View file

@ -1,4 +1,4 @@
/* $OpenBSD: ofw_regulator.h,v 1.8 2023/04/01 08:37:23 kettenis Exp $ */ /* $OpenBSD: ofw_regulator.h,v 1.9 2024/06/14 20:00:32 kettenis Exp $ */
/* /*
* Copyright (c) 2016 Mark Kettenis * Copyright (c) 2016 Mark Kettenis
* *
@ -31,6 +31,9 @@ struct regulator_device {
uint32_t rd_amp_min, rd_amp_max; uint32_t rd_amp_min, rd_amp_max;
uint32_t rd_ramp_delay; uint32_t rd_ramp_delay;
uint32_t rd_coupled;
uint32_t rd_max_spread;
LIST_ENTRY(regulator_device) rd_list; LIST_ENTRY(regulator_device) rd_list;
uint32_t rd_phandle; uint32_t rd_phandle;
}; };

View file

@ -812,6 +812,10 @@ probe_gmdid_display(struct drm_i915_private *i915, u16 *ver, u16 *rel, u16 *step
void __iomem *addr; void __iomem *addr;
u32 val; u32 val;
int i; int i;
int mmio_bar, mmio_size, mmio_type;
bus_space_tag_t bst;
bus_space_handle_t bsh;
bus_size_t memsize;
/* The caller expects to ver, rel and step to be initialized /* The caller expects to ver, rel and step to be initialized
* here, and there's no good way to check when there was a * here, and there's no good way to check when there was a
@ -822,9 +826,7 @@ probe_gmdid_display(struct drm_i915_private *i915, u16 *ver, u16 *rel, u16 *step
*rel = 0; *rel = 0;
*step = 0; *step = 0;
STUB(); #ifdef __linux__
return &no_display;
#ifdef notyet
addr = pci_iomap_range(pdev, 0, i915_mmio_reg_offset(GMD_ID_DISPLAY), sizeof(u32)); addr = pci_iomap_range(pdev, 0, i915_mmio_reg_offset(GMD_ID_DISPLAY), sizeof(u32));
if (!addr) { if (!addr) {
drm_err(&i915->drm, "Cannot map MMIO BAR to read display GMD_ID\n"); drm_err(&i915->drm, "Cannot map MMIO BAR to read display GMD_ID\n");
@ -833,6 +835,19 @@ probe_gmdid_display(struct drm_i915_private *i915, u16 *ver, u16 *rel, u16 *step
val = ioread32(addr); val = ioread32(addr);
pci_iounmap(pdev, addr); pci_iounmap(pdev, addr);
#else
mmio_bar = 0x10;
mmio_type = pci_mapreg_type(i915->pc, i915->tag, mmio_bar);
if (pci_mapreg_map(i915->pa, mmio_bar, mmio_type, 0,
&bst, &bsh, NULL, &memsize, 0)) {
drm_err(&i915->drm, "Cannot map MMIO BAR to read display GMD_ID\n");
return &no_display;
}
val = bus_space_read_4(bst, bsh, i915_mmio_reg_offset(GMD_ID_DISPLAY));
bus_space_unmap(bst, bsh, memsize);
#endif
if (val == 0) { if (val == 0) {
drm_dbg_kms(&i915->drm, "Device doesn't have display\n"); drm_dbg_kms(&i915->drm, "Device doesn't have display\n");
@ -851,7 +866,6 @@ probe_gmdid_display(struct drm_i915_private *i915, u16 *ver, u16 *rel, u16 *step
drm_err(&i915->drm, "Unrecognized display IP version %d.%02d; disabling display.\n", drm_err(&i915->drm, "Unrecognized display IP version %d.%02d; disabling display.\n",
*ver, *rel); *ver, *rel);
return &no_display; return &no_display;
#endif
} }
const struct intel_display_device_info * const struct intel_display_device_info *

View file

@ -388,6 +388,27 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915,
drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = 0x%016llx\n", reg_val); drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = 0x%016llx\n", reg_val);
/* Wa_14019821291 */
if (MEDIA_VER_FULL(i915) == IP_VER(13, 0)) {
/*
* This workaround is primarily implemented by the BIOS. We
* just need to figure out whether the BIOS has applied the
* workaround (meaning the programmed address falls within
* the DSM) and, if so, reserve that part of the DSM to
* prevent accidental reuse. The DSM location should be just
* below the WOPCM.
*/
u64 gscpsmi_base = intel_uncore_read64_2x32(uncore,
MTL_GSCPSMI_BASEADDR_LSB,
MTL_GSCPSMI_BASEADDR_MSB);
if (gscpsmi_base >= i915->dsm.stolen.start &&
gscpsmi_base < i915->dsm.stolen.end) {
*base = gscpsmi_base;
*size = i915->dsm.stolen.end - gscpsmi_base;
return;
}
}
switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) { switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) {
case GEN8_STOLEN_RESERVED_1M: case GEN8_STOLEN_RESERVED_1M:
*size = 1024 * 1024; *size = 1024 * 1024;

View file

@ -470,6 +470,9 @@
#define XEHP_PSS_MODE2 MCR_REG(0x703c) #define XEHP_PSS_MODE2 MCR_REG(0x703c)
#define SCOREBOARD_STALL_FLUSH_CONTROL REG_BIT(5) #define SCOREBOARD_STALL_FLUSH_CONTROL REG_BIT(5)
#define XEHP_PSS_CHICKEN MCR_REG(0x7044)
#define FD_END_COLLECT REG_BIT(5)
#define GEN7_SC_INSTDONE _MMIO(0x7100) #define GEN7_SC_INSTDONE _MMIO(0x7100)
#define GEN12_SC_INSTDONE_EXTRA _MMIO(0x7104) #define GEN12_SC_INSTDONE_EXTRA _MMIO(0x7104)
#define GEN12_SC_INSTDONE_EXTRA2 _MMIO(0x7108) #define GEN12_SC_INSTDONE_EXTRA2 _MMIO(0x7108)
@ -538,6 +541,9 @@
#define XEHP_SQCM MCR_REG(0x8724) #define XEHP_SQCM MCR_REG(0x8724)
#define EN_32B_ACCESS REG_BIT(30) #define EN_32B_ACCESS REG_BIT(30)
#define MTL_GSCPSMI_BASEADDR_LSB _MMIO(0x880c)
#define MTL_GSCPSMI_BASEADDR_MSB _MMIO(0x8810)
#define HSW_IDICR _MMIO(0x9008) #define HSW_IDICR _MMIO(0x9008)
#define IDIHASHMSK(x) (((x) & 0x3f) << 16) #define IDIHASHMSK(x) (((x) & 0x3f) << 16)
@ -1209,6 +1215,7 @@
#define GEN12_DISABLE_EARLY_READ REG_BIT(14) #define GEN12_DISABLE_EARLY_READ REG_BIT(14)
#define GEN12_ENABLE_LARGE_GRF_MODE REG_BIT(12) #define GEN12_ENABLE_LARGE_GRF_MODE REG_BIT(12)
#define GEN12_PUSH_CONST_DEREF_HOLD_DIS REG_BIT(8) #define GEN12_PUSH_CONST_DEREF_HOLD_DIS REG_BIT(8)
#define XELPG_DISABLE_TDL_SVHS_GATING REG_BIT(1)
#define GEN12_DISABLE_DOP_GATING REG_BIT(0) #define GEN12_DISABLE_DOP_GATING REG_BIT(0)
#define RT_CTRL MCR_REG(0xe530) #define RT_CTRL MCR_REG(0xe530)
@ -1221,6 +1228,8 @@
#define XEHP_HDC_CHICKEN0 MCR_REG(0xe5f0) #define XEHP_HDC_CHICKEN0 MCR_REG(0xe5f0)
#define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11) #define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11)
#define DIS_ATOMIC_CHAINING_TYPED_WRITES REG_BIT(3)
#define ICL_HDC_MODE MCR_REG(0xe5f4) #define ICL_HDC_MODE MCR_REG(0xe5f4)
#define EU_PERF_CNTL2 PERF_REG(0xe658) #define EU_PERF_CNTL2 PERF_REG(0xe658)

View file

@ -781,6 +781,9 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine,
/* Wa_18019271663:dg2 */ /* Wa_18019271663:dg2 */
wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE); wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE);
/* Wa_14019877138:dg2 */
wa_mcr_masked_en(wal, XEHP_PSS_CHICKEN, FD_END_COLLECT);
} }
static void xelpg_ctx_gt_tuning_init(struct intel_engine_cs *engine, static void xelpg_ctx_gt_tuning_init(struct intel_engine_cs *engine,
@ -826,6 +829,9 @@ static void xelpg_ctx_workarounds_init(struct intel_engine_cs *engine,
/* Wa_18019271663 */ /* Wa_18019271663 */
wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE); wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE);
/* Wa_14019877138 */
wa_mcr_masked_en(wal, XEHP_PSS_CHICKEN, FD_END_COLLECT);
} }
static void fakewa_disable_nestedbb_mode(struct intel_engine_cs *engine, static void fakewa_disable_nestedbb_mode(struct intel_engine_cs *engine,
@ -2338,6 +2344,14 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal)
LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK); LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK);
} }
if (IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 70), IP_VER(12, 71)) ||
IS_DG2(i915)) {
/* Wa_14015150844 */
wa_mcr_add(wal, XEHP_HDC_CHICKEN0, 0,
_MASKED_BIT_ENABLE(DIS_ATOMIC_CHAINING_TYPED_WRITES),
0, true);
}
if (IS_DG2_G11(i915) || IS_DG2_G10(i915)) { if (IS_DG2_G11(i915) || IS_DG2_G10(i915)) {
/* Wa_22014600077:dg2 */ /* Wa_22014600077:dg2 */
wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0,
@ -2887,10 +2901,14 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li
if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_B0, STEP_FOREVER) || if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_B0, STEP_FOREVER) ||
IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER) || IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_B0, STEP_FOREVER) ||
IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 74), IP_VER(12, 74))) IS_GFX_GT_IP_RANGE(gt, IP_VER(12, 74), IP_VER(12, 74))) {
/* Wa_14017856879 */ /* Wa_14017856879 */
wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN3, MTL_DISABLE_FIX_FOR_EOT_FLUSH); wa_mcr_masked_en(wal, GEN9_ROW_CHICKEN3, MTL_DISABLE_FIX_FOR_EOT_FLUSH);
/* Wa_14020495402 */
wa_mcr_masked_en(wal, GEN8_ROW_CHICKEN2, XELPG_DISABLE_TDL_SVHS_GATING);
}
if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) ||
IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0)) IS_GFX_GT_IP_STEP(gt, IP_VER(12, 71), STEP_A0, STEP_B0))
/* /*

View file

@ -2258,6 +2258,7 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
int mmio_bar, mmio_size, mmio_type; int mmio_bar, mmio_size, mmio_type;
int ret; int ret;
dev_priv->pa = pa;
dev_priv->pc = pa->pa_pc; dev_priv->pc = pa->pa_pc;
dev_priv->tag = pa->pa_tag; dev_priv->tag = pa->pa_tag;
dev_priv->iot = pa->pa_iot; dev_priv->iot = pa->pa_iot;

View file

@ -239,6 +239,7 @@ struct inteldrm_softc {
struct i915_dsm dsm; struct i915_dsm dsm;
#ifdef __OpenBSD__ #ifdef __OpenBSD__
struct pci_attach_args *pa;
pci_chipset_tag_t pc; pci_chipset_tag_t pc;
pcitag_t tag; pcitag_t tag;
struct extent *memex; struct extent *memex;

View file

@ -290,20 +290,25 @@ static void intel_device_info_subplatform_init(struct drm_i915_private *i915)
static void ip_ver_read(struct drm_i915_private *i915, u32 offset, struct intel_ip_version *ip) static void ip_ver_read(struct drm_i915_private *i915, u32 offset, struct intel_ip_version *ip)
{ {
STUB(); #ifdef __linux__
#ifdef notyet
struct pci_dev *pdev = to_pci_dev(i915->drm.dev); struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
void __iomem *addr; void __iomem *addr;
#endif
u32 val; u32 val;
u8 expected_ver = ip->ver; u8 expected_ver = ip->ver;
u8 expected_rel = ip->rel; u8 expected_rel = ip->rel;
#ifdef __linux__
addr = pci_iomap_range(pdev, 0, offset, sizeof(u32)); addr = pci_iomap_range(pdev, 0, offset, sizeof(u32));
if (drm_WARN_ON(&i915->drm, !addr)) if (drm_WARN_ON(&i915->drm, !addr))
return; return;
val = ioread32(addr); val = ioread32(addr);
pci_iounmap(pdev, addr); pci_iounmap(pdev, addr);
#else
val = bus_space_read_4(i915->vga_regs->bst, i915->vga_regs->bsh,
offset);
#endif
ip->ver = REG_FIELD_GET(GMD_ID_ARCH_MASK, val); ip->ver = REG_FIELD_GET(GMD_ID_ARCH_MASK, val);
ip->rel = REG_FIELD_GET(GMD_ID_RELEASE_MASK, val); ip->rel = REG_FIELD_GET(GMD_ID_RELEASE_MASK, val);
@ -314,7 +319,6 @@ static void ip_ver_read(struct drm_i915_private *i915, u32 offset, struct intel_
drm_dbg(&i915->drm, drm_dbg(&i915->drm,
"Hardware reports GMD IP version %u.%u (REG[0x%x] = 0x%08x) but minimum expected is %u.%u\n", "Hardware reports GMD IP version %u.%u (REG[0x%x] = 0x%08x) but minimum expected is %u.%u\n",
ip->ver, ip->rel, offset, val, expected_ver, expected_rel); ip->ver, ip->rel, offset, val, expected_ver, expected_rel);
#endif
} }
/* /*

View file

@ -1,4 +1,4 @@
/* $OpenBSD: rnd.c,v 1.227 2024/06/04 08:26:11 claudio Exp $ */ /* $OpenBSD: rnd.c,v 1.228 2024/06/14 10:17:05 claudio Exp $ */
/* /*
* Copyright (c) 2011,2020 Theo de Raadt. * Copyright (c) 2011,2020 Theo de Raadt.
@ -172,8 +172,8 @@ const struct filterops randomwrite_filtops = {
/* /*
* This function mixes entropy and timing into the entropy input ring. * This function mixes entropy and timing into the entropy input ring.
*/ */
void static void
enqueue_randomness(u_int val) add_event_data(u_int val)
{ {
struct rand_event *rep; struct rand_event *rep;
int e; int e;
@ -182,6 +182,12 @@ enqueue_randomness(u_int val)
rep = &rnd_event_space[e]; rep = &rnd_event_space[e];
rep->re_time += cpu_rnd_messybits(); rep->re_time += cpu_rnd_messybits();
rep->re_val += val; rep->re_val += val;
}
void
enqueue_randomness(u_int val)
{
add_event_data(val);
if (rnd_cold) { if (rnd_cold) {
dequeue_randomness(NULL); dequeue_randomness(NULL);
@ -248,9 +254,6 @@ dequeue_randomness(void *v)
u_int32_t buf[2]; u_int32_t buf[2];
u_int startp, startc, i; u_int startp, startc, i;
if (!rnd_cold)
timeout_del(&rnd_timeout);
/* Some very new damage */ /* Some very new damage */
startp = rnd_event_prod - QEVCONSUME; startp = rnd_event_prod - QEVCONSUME;
for (i = 0; i < QEVCONSUME; i++) { for (i = 0; i < QEVCONSUME; i++) {
@ -304,10 +307,8 @@ extract_entropy(u_int8_t *buf)
/* /*
* Modify pool so next hash will produce different results. * Modify pool so next hash will produce different results.
* During boot-time enqueue/dequeue stage, avoid recursion. */
*/ add_event_data(extract_pool[0]);
if (!rnd_cold)
enqueue_randomness(extract_pool[0]);
dequeue_randomness(NULL); dequeue_randomness(NULL);
/* Wipe data from memory */ /* Wipe data from memory */

View file

@ -1,4 +1,4 @@
/* $OpenBSD: uipc_socket.c,v 1.335 2024/05/17 19:11:14 mvs Exp $ */ /* $OpenBSD: uipc_socket.c,v 1.336 2024/06/14 08:32:22 mvs Exp $ */
/* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */
/* /*
@ -166,6 +166,7 @@ soalloc(const struct protosw *prp, int wait)
} }
break; break;
case AF_KEY: case AF_KEY:
case AF_ROUTE:
case AF_UNIX: case AF_UNIX:
so->so_snd.sb_flags |= SB_MTXLOCK; so->so_snd.sb_flags |= SB_MTXLOCK;
so->so_rcv.sb_flags |= SB_MTXLOCK; so->so_rcv.sb_flags |= SB_MTXLOCK;

View file

@ -1,4 +1,4 @@
/* $OpenBSD: rtsock.c,v 1.373 2023/12/03 10:51:17 mvs Exp $ */ /* $OpenBSD: rtsock.c,v 1.374 2024/06/14 08:32:22 mvs Exp $ */
/* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */ /* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */
/* /*
@ -313,10 +313,12 @@ route_rcvd(struct socket *so)
* If we are in a FLUSH state, check if the buffer is * If we are in a FLUSH state, check if the buffer is
* empty so that we can clear the flag. * empty so that we can clear the flag.
*/ */
mtx_enter(&so->so_rcv.sb_mtx);
if (((rop->rop_flags & ROUTECB_FLAG_FLUSH) != 0) && if (((rop->rop_flags & ROUTECB_FLAG_FLUSH) != 0) &&
((sbspace(rop->rop_socket, &rop->rop_socket->so_rcv) == ((sbspace(so, &so->so_rcv) == so->so_rcv.sb_hiwat)))
rop->rop_socket->so_rcv.sb_hiwat)))
rop->rop_flags &= ~ROUTECB_FLAG_FLUSH; rop->rop_flags &= ~ROUTECB_FLAG_FLUSH;
mtx_leave(&so->so_rcv.sb_mtx);
} }
int int
@ -478,8 +480,14 @@ rtm_senddesync(struct socket *so)
*/ */
desync_mbuf = rtm_msg1(RTM_DESYNC, NULL); desync_mbuf = rtm_msg1(RTM_DESYNC, NULL);
if (desync_mbuf != NULL) { if (desync_mbuf != NULL) {
if (sbappendaddr(so, &so->so_rcv, &route_src, int ret;
desync_mbuf, NULL) != 0) {
mtx_enter(&so->so_rcv.sb_mtx);
ret = sbappendaddr(so, &so->so_rcv, &route_src,
desync_mbuf, NULL);
mtx_leave(&so->so_rcv.sb_mtx);
if (ret != 0) {
rop->rop_flags &= ~ROUTECB_FLAG_DESYNC; rop->rop_flags &= ~ROUTECB_FLAG_DESYNC;
sorwakeup(rop->rop_socket); sorwakeup(rop->rop_socket);
return; return;
@ -586,6 +594,7 @@ rtm_sendup(struct socket *so, struct mbuf *m0)
{ {
struct rtpcb *rop = sotortpcb(so); struct rtpcb *rop = sotortpcb(so);
struct mbuf *m; struct mbuf *m;
int send_desync = 0;
soassertlocked(so); soassertlocked(so);
@ -593,8 +602,13 @@ rtm_sendup(struct socket *so, struct mbuf *m0)
if (m == NULL) if (m == NULL)
return (ENOMEM); return (ENOMEM);
mtx_enter(&so->so_rcv.sb_mtx);
if (sbspace(so, &so->so_rcv) < (2 * MSIZE) || if (sbspace(so, &so->so_rcv) < (2 * MSIZE) ||
sbappendaddr(so, &so->so_rcv, &route_src, m, NULL) == 0) { sbappendaddr(so, &so->so_rcv, &route_src, m, NULL) == 0)
send_desync = 1;
mtx_leave(&so->so_rcv.sb_mtx);
if (send_desync) {
/* Flag socket as desync'ed and flush required */ /* Flag socket as desync'ed and flush required */
rop->rop_flags |= ROUTECB_FLAG_DESYNC | ROUTECB_FLAG_FLUSH; rop->rop_flags |= ROUTECB_FLAG_DESYNC | ROUTECB_FLAG_FLUSH;
rtm_senddesync(so); rtm_senddesync(so);

View file

@ -1,4 +1,4 @@
/* $OpenBSD: tags.c,v 1.27 2023/03/29 19:09:04 op Exp $ */ /* $OpenBSD: tags.c,v 1.28 2024/06/14 13:59:26 op Exp $ */
/* /*
* This file is in the public domain. * This file is in the public domain.
@ -340,7 +340,7 @@ int
addctag(char *s) addctag(char *s)
{ {
struct ctag *t = NULL; struct ctag *t = NULL;
char *l; char *l, *c;
if ((t = malloc(sizeof(struct ctag))) == NULL) { if ((t = malloc(sizeof(struct ctag))) == NULL) {
dobeep(); dobeep();
@ -357,6 +357,15 @@ addctag(char *s)
*l++ = '\0'; *l++ = '\0';
if (*l == '\0') if (*l == '\0')
goto cleanup; goto cleanup;
/*
* Newer universal ctags format abuse vi comments in the
* pattern to store extra metadata. Since we don't support it
* remove it so the pattern is not mangled.
*/
if ((c = strstr(l, ";\"")) != NULL)
*c = '\0';
t->pat = strip(l, strlen(l)); t->pat = strip(l, strlen(l));
if (RB_INSERT(tagtree, &tags, t) != NULL) { if (RB_INSERT(tagtree, &tags, t) != NULL) {
free(t); free(t);

View file

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keyscan.1,v 1.49 2023/02/10 06:41:53 jmc Exp $ .\" $OpenBSD: ssh-keyscan.1,v 1.51 2024/06/14 05:20:34 jmc Exp $
.\" .\"
.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. .\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
.\" .\"
@ -6,7 +6,7 @@
.\" permitted provided that due credit is given to the author and the .\" permitted provided that due credit is given to the author and the
.\" OpenBSD project by leaving this copyright notice intact. .\" OpenBSD project by leaving this copyright notice intact.
.\" .\"
.Dd $Mdocdate: February 10 2023 $ .Dd $Mdocdate: June 14 2024 $
.Dt SSH-KEYSCAN 1 .Dt SSH-KEYSCAN 1
.Os .Os
.Sh NAME .Sh NAME
@ -14,7 +14,7 @@
.Nd gather SSH public keys from servers .Nd gather SSH public keys from servers
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm ssh-keyscan .Nm ssh-keyscan
.Op Fl 46cDHv .Op Fl 46cDHqv
.Op Fl f Ar file .Op Fl f Ar file
.Op Fl O Ar option .Op Fl O Ar option
.Op Fl p Ar port .Op Fl p Ar port
@ -116,6 +116,9 @@ The default is to print both.
Connect to Connect to
.Ar port .Ar port
on the remote host. on the remote host.
.It Fl q
Quiet mode:
do not print server host name and banners in comments.
.It Fl T Ar timeout .It Fl T Ar timeout
Set the timeout for connection attempts. Set the timeout for connection attempts.
If If

View file

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: ssh_config.5,v 1.394 2024/02/21 06:01:13 djm Exp $ .\" $OpenBSD: ssh_config.5,v 1.395 2024/06/14 05:01:22 djm Exp $
.Dd $Mdocdate: February 21 2024 $ .Dd $Mdocdate: June 14 2024 $
.Dt SSH_CONFIG 5 .Dt SSH_CONFIG 5
.Os .Os
.Sh NAME .Sh NAME
@ -1262,8 +1262,12 @@ it may be zero or more of:
and and
.Cm skey . .Cm skey .
.It Cm KexAlgorithms .It Cm KexAlgorithms
Specifies the available KEX (Key Exchange) algorithms. Specifies the permitted KEX (Key Exchange) algorithms that will be used and
their preference order.
The selected algorithm will the the first algorithm in this list that
the server also supports.
Multiple algorithms must be comma-separated. Multiple algorithms must be comma-separated.
.Pp
If the specified list begins with a If the specified list begins with a
.Sq + .Sq +
character, then the specified algorithms will be appended to the default set character, then the specified algorithms will be appended to the default set
@ -1276,6 +1280,7 @@ If the specified list begins with a
.Sq ^ .Sq ^
character, then the specified algorithms will be placed at the head of the character, then the specified algorithms will be placed at the head of the
default set. default set.
.Pp
The default is: The default is:
.Bd -literal -offset indent .Bd -literal -offset indent
sntrup761x25519-sha512@openssh.com, sntrup761x25519-sha512@openssh.com,
@ -1287,7 +1292,7 @@ diffie-hellman-group18-sha512,
diffie-hellman-group14-sha256 diffie-hellman-group14-sha256
.Ed .Ed
.Pp .Pp
The list of available key exchange algorithms may also be obtained using The list of supported key exchange algorithms may also be obtained using
.Qq ssh -Q kex . .Qq ssh -Q kex .
.It Cm KnownHostsCommand .It Cm KnownHostsCommand
Specifies a command to use to obtain a list of host keys, in addition to Specifies a command to use to obtain a list of host keys, in addition to

View file

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: sshd_config.5,v 1.362 2024/06/13 15:06:33 naddy Exp $ .\" $OpenBSD: sshd_config.5,v 1.363 2024/06/14 05:01:22 djm Exp $
.Dd $Mdocdate: June 13 2024 $ .Dd $Mdocdate: June 14 2024 $
.Dt SSHD_CONFIG 5 .Dt SSHD_CONFIG 5
.Os .Os
.Sh NAME .Sh NAME
@ -1004,9 +1004,13 @@ file on logout.
The default is The default is
.Cm yes . .Cm yes .
.It Cm KexAlgorithms .It Cm KexAlgorithms
Specifies the available KEX (Key Exchange) algorithms. Specifies the permitted KEX (Key Exchange) algorithms that the server will
offer to clients.
The ordering of this list is not important, as the client specifies the
preference order.
Multiple algorithms must be comma-separated. Multiple algorithms must be comma-separated.
Alternately if the specified list begins with a .Pp
If the specified list begins with a
.Sq + .Sq +
character, then the specified algorithms will be appended to the default set character, then the specified algorithms will be appended to the default set
instead of replacing them. instead of replacing them.
@ -1018,6 +1022,7 @@ If the specified list begins with a
.Sq ^ .Sq ^
character, then the specified algorithms will be placed at the head of the character, then the specified algorithms will be placed at the head of the
default set. default set.
.Pp
The supported algorithms are: The supported algorithms are:
.Pp .Pp
.Bl -item -compact -offset indent .Bl -item -compact -offset indent
@ -1059,7 +1064,7 @@ diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,
diffie-hellman-group14-sha256 diffie-hellman-group14-sha256
.Ed .Ed
.Pp .Pp
The list of available key exchange algorithms may also be obtained using The list of supported key exchange algorithms may also be obtained using
.Qq ssh -Q KexAlgorithms . .Qq ssh -Q KexAlgorithms .
.It Cm ListenAddress .It Cm ListenAddress
Specifies the local addresses Specifies the local addresses