sync with OpenBSD -current
This commit is contained in:
parent
f4a22ff4b2
commit
9dfe537fef
85 changed files with 12490 additions and 6835 deletions
|
@ -44,8 +44,8 @@ sleep 8
|
|||
${SSH} -F $OBJ/ssh_config somehost true || fail "authfail not expired"
|
||||
|
||||
verbose "penalty for no authentication"
|
||||
${SSHKEYSCAN} -p $PORT 127.0.0.1 >/dev/null 2>&1 || fatal "keyscan failed"
|
||||
${SSHKEYSCAN} -t ssh-ed25519 -p $PORT 127.0.0.1 >/dev/null || fatal "keyscan failed"
|
||||
|
||||
# Repeat attempt should be penalised
|
||||
${SSHKEYSCAN} -p $PORT 127.0.0.1 >/dev/null 2>&1 && fail "keyscan not rejected"
|
||||
${SSHKEYSCAN} -t ssh-ed25519 -p $PORT 127.0.0.1 >/dev/null 2>&1 && fail "keyscan not rejected"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ccp.c,v 1.4 2024/06/12 12:54:54 bluhm Exp $ */
|
||||
/* $OpenBSD: ccp.c,v 1.5 2024/06/13 17:59:08 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 David Gwynne <dlg@openbsd.org>
|
||||
|
@ -58,7 +58,7 @@ ccp_attach(struct ccp_softc *sc)
|
|||
timeout_set(&sc->sc_tick, ccp_rng, sc);
|
||||
ccp_rng(sc);
|
||||
|
||||
if (sc->sc_psp_attached)
|
||||
if (sc->sc_psp_attached != 0)
|
||||
printf(", RNG\n");
|
||||
else
|
||||
printf(": RNG\n");
|
||||
|
@ -127,8 +127,6 @@ psp_attach(struct ccp_softc *sc)
|
|||
if (psp_get_pstatus(&pst) || pst.state != 0)
|
||||
goto fail_3;
|
||||
|
||||
printf(", SEV");
|
||||
|
||||
/*
|
||||
* create and map Trusted Memory Region (TMR); size 1 Mbyte,
|
||||
* needs to be aligend to 1 Mbyte.
|
||||
|
@ -158,6 +156,8 @@ psp_attach(struct ccp_softc *sc)
|
|||
if (psp_init(&init))
|
||||
goto fail_7;
|
||||
|
||||
printf(", SEV");
|
||||
|
||||
psp_get_pstatus(&pst);
|
||||
if ((pst.state == 1) && (pst.cfges_build & 0x1))
|
||||
printf(", SEV-ES");
|
||||
|
@ -184,6 +184,7 @@ fail_0:
|
|||
bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmd_map);
|
||||
|
||||
ccp_softc = NULL;
|
||||
sc->sc_psp_attached = -1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -240,11 +241,8 @@ ccp_docmd(struct ccp_softc *sc, int cmd, uint64_t paddr)
|
|||
|
||||
/* Did PSP sent a response code? */
|
||||
if (status & PSP_CMDRESP_RESPONSE) {
|
||||
if ((status & PSP_STATUS_MASK) != PSP_STATUS_SUCCESS) {
|
||||
printf("%s: command failed: 0x%x\n", __func__,
|
||||
(status & PSP_STATUS_MASK));
|
||||
if ((status & PSP_STATUS_MASK) != PSP_STATUS_SUCCESS)
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
@ -265,12 +263,11 @@ psp_init(struct psp_init *uinit)
|
|||
init->tmr_length = uinit->tmr_length;
|
||||
|
||||
ret = ccp_docmd(sc, PSP_CMD_INIT, sc->sc_cmd_map->dm_segs[0].ds_addr);
|
||||
|
||||
wbinvd_on_all_cpus();
|
||||
|
||||
if (ret != 0)
|
||||
return (EIO);
|
||||
|
||||
wbinvd_on_all_cpus();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ccpvar.h,v 1.2 2024/06/12 12:54:54 bluhm Exp $ */
|
||||
/* $OpenBSD: ccpvar.h,v 1.3 2024/06/13 17:59:08 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 David Gwynne <dlg@openbsd.org>
|
||||
|
@ -26,7 +26,6 @@ struct ccp_softc {
|
|||
|
||||
struct timeout sc_tick;
|
||||
|
||||
bus_size_t sc_size;
|
||||
int sc_psp_attached;
|
||||
|
||||
#ifdef __amd64__
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ccp_pci.c,v 1.10 2024/06/12 12:54:54 bluhm Exp $ */
|
||||
/* $OpenBSD: ccp_pci.c,v 1.11 2024/06/13 17:59:08 bluhm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 David Gwynne <dlg@openbsd.org>
|
||||
|
@ -74,7 +74,7 @@ ccp_pci_attach(struct device *parent, struct device *self, void *aux)
|
|||
}
|
||||
|
||||
if (pci_mapreg_map(pa, CCP_PCI_BAR, memtype, 0,
|
||||
&sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_size, 0) != 0) {
|
||||
&sc->sc_iot, &sc->sc_ioh, NULL, NULL, 0) != 0) {
|
||||
printf(": cannot map registers\n");
|
||||
return;
|
||||
}
|
||||
|
@ -107,7 +107,6 @@ psp_pci_attach(struct device *parent, struct device *self, void *aux)
|
|||
if (pci_intr_map_msix(pa, 0, &ih) != 0 &&
|
||||
pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
|
||||
printf(": couldn't map interrupt\n");
|
||||
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -117,10 +116,14 @@ psp_pci_attach(struct device *parent, struct device *self, void *aux)
|
|||
if (sc->sc_ih != NULL)
|
||||
printf(": %s", intrstr);
|
||||
|
||||
if (psp_attach(sc)) {
|
||||
/* enable interrupts */
|
||||
bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTEN, -1);
|
||||
if (!psp_attach(sc)) {
|
||||
pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
|
||||
sc->sc_ih = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* enable interrupts */
|
||||
bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTEN, -1);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: drm_linux.c,v 1.113 2024/06/03 12:48:25 claudio Exp $ */
|
||||
/* $OpenBSD: drm_linux.c,v 1.114 2024/06/13 18:05:54 kettenis Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2013 Jonathan Gray <jsg@openbsd.org>
|
||||
* Copyright (c) 2015, 2016 Mark Kettenis <kettenis@openbsd.org>
|
||||
|
@ -1521,6 +1521,12 @@ acpi_format_exception(acpi_status status)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
acpi_target_system_state(void)
|
||||
{
|
||||
return acpi_softc->sc_state;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SLIST_HEAD(,backlight_device) backlight_device_list =
|
||||
|
|
|
@ -2308,19 +2308,25 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
|
|||
intel_device_info_driver_create(dev_priv, dev->pdev->device, info);
|
||||
|
||||
mmio_bar = (GRAPHICS_VER(dev_priv) == 2) ? 0x14 : 0x10;
|
||||
/* Before gen4, the registers and the GTT are behind different BARs.
|
||||
|
||||
/* from intel_uncore_setup_mmio() */
|
||||
|
||||
/*
|
||||
* Before gen4, the registers and the GTT are behind different BARs.
|
||||
* However, from gen4 onwards, the registers and the GTT are shared
|
||||
* in the same BAR, so we want to restrict this ioremap from
|
||||
* clobbering the GTT which we want ioremap_wc instead. Fortunately,
|
||||
* the register BAR remains the same size for all the earlier
|
||||
* generations up to Ironlake.
|
||||
* For dgfx chips register range is expanded to 4MB, and this larger
|
||||
* range is also used for integrated gpus beginning with Meteor Lake.
|
||||
*/
|
||||
if (GRAPHICS_VER(dev_priv) < 5)
|
||||
mmio_size = 512 * 1024;
|
||||
else if (IS_DGFX(dev_priv))
|
||||
if (IS_DGFX(dev_priv) || GRAPHICS_VER_FULL(dev_priv) >= IP_VER(12, 70))
|
||||
mmio_size = 4 * 1024 * 1024;
|
||||
else
|
||||
else if (GRAPHICS_VER(dev_priv) >= 5)
|
||||
mmio_size = 2 * 1024 * 1024;
|
||||
else
|
||||
mmio_size = 512 * 1024;
|
||||
|
||||
mmio_type = pci_mapreg_type(pa->pa_pc, pa->pa_tag, mmio_bar);
|
||||
if (pci_mapreg_map(pa, mmio_bar, mmio_type, BUS_SPACE_MAP_LINEAR,
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "acpi.h"
|
||||
#if NACPI > 0
|
||||
#define CONFIG_ACPI 1
|
||||
#define CONFIG_ACPI_SLEEP 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -86,4 +86,6 @@ struct notifier_block;
|
|||
int register_acpi_notifier(struct notifier_block *);
|
||||
int unregister_acpi_notifier(struct notifier_block *);
|
||||
|
||||
int acpi_target_system_state(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh-keyscan.c,v 1.157 2024/05/06 19:26:17 tobias Exp $ */
|
||||
/* $OpenBSD: ssh-keyscan.c,v 1.158 2024/06/14 00:25:25 djm Exp $ */
|
||||
/*
|
||||
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
|
||||
*
|
||||
|
@ -76,6 +76,8 @@ int found_one = 0; /* Successfully found a key */
|
|||
|
||||
int hashalg = -1; /* Hash for SSHFP records or -1 for all */
|
||||
|
||||
int quiet = 0; /* Don't print key comment lines */
|
||||
|
||||
#define MAXMAXFD 256
|
||||
|
||||
/* The number of seconds after which to give up on a TCP connection */
|
||||
|
@ -516,8 +518,10 @@ congreet(int s)
|
|||
confree(s);
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "%c %s:%d %s\n", print_sshfp ? ';' : '#',
|
||||
c->c_name, ssh_port, chop(buf));
|
||||
if (!quiet) {
|
||||
fprintf(stdout, "%c %s:%d %s\n", print_sshfp ? ';' : '#',
|
||||
c->c_name, ssh_port, chop(buf));
|
||||
}
|
||||
keygrab_ssh2(c);
|
||||
confree(s);
|
||||
}
|
||||
|
@ -639,7 +643,7 @@ static void
|
|||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: ssh-keyscan [-46cDHv] [-f file] [-O option] [-p port] [-T timeout]\n"
|
||||
"usage: ssh-keyscan [-46cDHqv] [-f file] [-O option] [-p port] [-T timeout]\n"
|
||||
" [-t type] [host | addrlist namelist]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -664,7 +668,7 @@ main(int argc, char **argv)
|
|||
if (argc <= 1)
|
||||
usage();
|
||||
|
||||
while ((opt = getopt(argc, argv, "cDHv46O:p:T:t:f:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "cDHqv46O:p:T:t:f:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'H':
|
||||
hash_hosts = 1;
|
||||
|
@ -699,6 +703,9 @@ main(int argc, char **argv)
|
|||
else
|
||||
fatal("Too high debugging level.");
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case 'f':
|
||||
if (strcmp(optarg, "-") == 0)
|
||||
optarg = NULL;
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $OpenBSD: sshd_config.5,v 1.361 2024/06/12 22:36:00 djm Exp $
|
||||
.Dd $Mdocdate: June 12 2024 $
|
||||
.\" $OpenBSD: sshd_config.5,v 1.362 2024/06/13 15:06:33 naddy Exp $
|
||||
.Dd $Mdocdate: June 13 2024 $
|
||||
.Dt SSHD_CONFIG 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -1604,7 +1604,7 @@ Repeated penalties will accumulate up to this maximum.
|
|||
.It Cm min:duration
|
||||
Specifies the minimum penalty that must accrue before enforcement begins
|
||||
(default: 15s).
|
||||
.It Cm max-sources4:number max-sources6:number
|
||||
.It Cm max-sources4:number , max-sources6:number
|
||||
Specifies the maximum number of client IPv4 and IPv6 address ranges to
|
||||
track for penalties (default: 65536 for both).
|
||||
.It Cm overflow:mode
|
||||
|
|
|
@ -1279,7 +1279,8 @@ daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h $(srcdir)/daemon/daemon.h
|
|||
$(srcdir)/util/edns.h $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \
|
||||
$(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/services/localzone.h \
|
||||
$(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/respip/respip.h \
|
||||
$(srcdir)/util/random.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h
|
||||
$(srcdir)/util/random.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h \
|
||||
$(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h
|
||||
remote.lo remote.o: $(srcdir)/daemon/remote.c config.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/worker.h \
|
||||
$(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h \
|
||||
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/netevent.h \
|
||||
|
@ -1356,7 +1357,7 @@ testbound.lo testbound.o: $(srcdir)/testcode/testbound.c config.h $(srcdir)/test
|
|||
$(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/tube.h \
|
||||
$(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/services/localzone.h $(srcdir)/services/view.h \
|
||||
$(srcdir)/services/authzone.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/libunbound/unbound.h \
|
||||
$(srcdir)/respip/respip.h $(srcdir)/util/net_help.h $(srcdir)/util/ub_event.h
|
||||
$(srcdir)/respip/respip.h $(srcdir)/util/net_help.h $(srcdir)/util/ub_event.h $(srcdir)/daemon/worker.h
|
||||
testpkts.lo testpkts.o: $(srcdir)/testcode/testpkts.c config.h $(srcdir)/testcode/testpkts.h \
|
||||
$(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/pkthdr.h \
|
||||
$(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h
|
||||
|
@ -1429,7 +1430,7 @@ fake_event.lo fake_event.o: $(srcdir)/testcode/fake_event.c config.h $(srcdir)/t
|
|||
$(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/services/modstack.h $(srcdir)/services/rpz.h \
|
||||
$(srcdir)/services/localzone.h $(srcdir)/services/view.h $(srcdir)/sldns/sbuffer.h $(srcdir)/services/authzone.h \
|
||||
$(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/libunbound/unbound.h $(srcdir)/respip/respip.h \
|
||||
$(srcdir)/sldns/wire2str.h $(srcdir)/sldns/str2wire.h $(srcdir)/daemon/remote.h
|
||||
$(srcdir)/sldns/wire2str.h $(srcdir)/sldns/str2wire.h $(srcdir)/daemon/remote.h $(srcdir)/util/storage/slabhash.h $(srcdir)/daemon/daemon.h
|
||||
lock_verify.lo lock_verify.o: $(srcdir)/testcode/lock_verify.c config.h $(srcdir)/util/log.h $(srcdir)/util/rbtree.h \
|
||||
$(srcdir)/util/locks.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
|
||||
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/module.h \
|
||||
|
@ -1485,7 +1486,8 @@ context.lo context.o: $(srcdir)/libunbound/context.c config.h $(srcdir)/libunbou
|
|||
$(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
|
||||
$(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
|
||||
$(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h \
|
||||
$(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/util/edns.h
|
||||
$(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/util/edns.h \
|
||||
$(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h
|
||||
libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbound/unbound.h \
|
||||
$(srcdir)/libunbound/unbound-event.h config.h $(srcdir)/libunbound/context.h $(srcdir)/util/locks.h \
|
||||
$(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \
|
||||
|
@ -1497,7 +1499,8 @@ libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbou
|
|||
$(srcdir)/sldns/sbuffer.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/util/netevent.h \
|
||||
$(srcdir)/dnscrypt/dnscrypt.h $(srcdir)/services/cache/rrset.h \
|
||||
$(srcdir)/util/storage/slabhash.h $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h \
|
||||
$(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h
|
||||
$(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h \
|
||||
$(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h
|
||||
libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h $(srcdir)/libunbound/libworker.h \
|
||||
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
|
||||
$(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \
|
||||
|
@ -1511,8 +1514,7 @@ libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h $(srcdir)/li
|
|||
$(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/outbound_list.h \
|
||||
$(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/regional.h $(srcdir)/util/random.h \
|
||||
$(srcdir)/util/storage/lookup3.h $(srcdir)/util/net_help.h $(srcdir)/util/data/dname.h \
|
||||
$(srcdir)/util/data/msgencode.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h \
|
||||
$(srcdir)/sldns/str2wire.h
|
||||
$(srcdir)/util/data/msgencode.h $(srcdir)/sldns/str2wire.h
|
||||
unbound-host.lo unbound-host.o: $(srcdir)/smallapp/unbound-host.c config.h $(srcdir)/libunbound/unbound.h \
|
||||
$(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.h
|
||||
asynclook.lo asynclook.o: $(srcdir)/testcode/asynclook.c config.h $(srcdir)/libunbound/unbound.h \
|
||||
|
|
139
usr.sbin/unbound/ax_pkg_swig.m4
Normal file
139
usr.sbin/unbound/ax_pkg_swig.m4
Normal file
|
@ -0,0 +1,139 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro searches for a SWIG installation on your system. If found,
|
||||
# then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is
|
||||
# found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd.
|
||||
#
|
||||
# You can use the optional first argument to check if the version of the
|
||||
# available SWIG is greater than or equal to the value of the argument. It
|
||||
# should have the format: N[.N[.N]] (N is a number between 0 and 999. Only
|
||||
# the first N is mandatory.) If the version argument is given (e.g.
|
||||
# 1.3.17), AX_PKG_SWIG checks that the swig package is this version number
|
||||
# or higher.
|
||||
#
|
||||
# As usual, action-if-found is executed if SWIG is found, otherwise
|
||||
# action-if-not-found is executed.
|
||||
#
|
||||
# In configure.in, use as:
|
||||
#
|
||||
# AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ])
|
||||
# AX_SWIG_ENABLE_CXX
|
||||
# AX_SWIG_MULTI_MODULE_SUPPORT
|
||||
# AX_SWIG_PYTHON
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
|
||||
# Copyright (c) 2008 Alan W. Irwin
|
||||
# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
|
||||
# Copyright (c) 2008 Andrew Collier
|
||||
# Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
|
||||
# Copyright (c) 2018 Reini Urban <rurban@cpan.org>
|
||||
# Copyright (c) 2021 Vincent Danjean <Vincent.Danjean@ens-lyon.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; either version 2 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 15
|
||||
|
||||
AC_DEFUN([AX_PKG_SWIG],[
|
||||
# Find path to the "swig" executable.
|
||||
AC_PATH_PROGS([SWIG],[swig swig3.0 swig2.0])
|
||||
if test -z "$SWIG" ; then
|
||||
m4_ifval([$3],[$3],[:])
|
||||
elif test -z "$1" ; then
|
||||
m4_ifval([$2],[$2],[:])
|
||||
else
|
||||
AC_MSG_CHECKING([SWIG version])
|
||||
[swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
|
||||
AC_MSG_RESULT([$swig_version])
|
||||
if test -n "$swig_version" ; then
|
||||
# Calculate the required version number components
|
||||
[required=$1]
|
||||
[required_major=`echo $required | sed 's/[^0-9].*//'`]
|
||||
if test -z "$required_major" ; then
|
||||
[required_major=0]
|
||||
fi
|
||||
[required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
|
||||
[required_minor=`echo $required | sed 's/[^0-9].*//'`]
|
||||
if test -z "$required_minor" ; then
|
||||
[required_minor=0]
|
||||
fi
|
||||
[required=`echo $required. | sed 's/[0-9]*[^0-9]//'`]
|
||||
[required_patch=`echo $required | sed 's/[^0-9].*//'`]
|
||||
if test -z "$required_patch" ; then
|
||||
[required_patch=0]
|
||||
fi
|
||||
# Calculate the available version number components
|
||||
[available=$swig_version]
|
||||
[available_major=`echo $available | sed 's/[^0-9].*//'`]
|
||||
if test -z "$available_major" ; then
|
||||
[available_major=0]
|
||||
fi
|
||||
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
|
||||
[available_minor=`echo $available | sed 's/[^0-9].*//'`]
|
||||
if test -z "$available_minor" ; then
|
||||
[available_minor=0]
|
||||
fi
|
||||
[available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
|
||||
[available_patch=`echo $available | sed 's/[^0-9].*//'`]
|
||||
if test -z "$available_patch" ; then
|
||||
[available_patch=0]
|
||||
fi
|
||||
# Convert the version tuple into a single number for easier comparison.
|
||||
# Using base 100 should be safe since SWIG internally uses BCD values
|
||||
# to encode its version number.
|
||||
required_swig_vernum=`expr $required_major \* 10000 \
|
||||
\+ $required_minor \* 100 \+ $required_patch`
|
||||
available_swig_vernum=`expr $available_major \* 10000 \
|
||||
\+ $available_minor \* 100 \+ $available_patch`
|
||||
|
||||
if test $available_swig_vernum -lt $required_swig_vernum; then
|
||||
AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.])
|
||||
SWIG=''
|
||||
m4_ifval([$3],[$3],[])
|
||||
else
|
||||
AC_MSG_CHECKING([for SWIG library])
|
||||
SWIG_LIB=`$SWIG -swiglib | tr '\r\n' ' '`
|
||||
AC_MSG_RESULT([$SWIG_LIB])
|
||||
m4_ifval([$2],[$2],[])
|
||||
fi
|
||||
else
|
||||
AC_MSG_WARN([cannot determine SWIG version])
|
||||
SWIG=''
|
||||
m4_ifval([$3],[$3],[])
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([SWIG_LIB])
|
||||
])
|
|
@ -1,5 +1,5 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
|
@ -14,24 +14,28 @@
|
|||
# flags that are needed. (The user can also force certain compiler
|
||||
# flags/libs to be tested by setting these environment variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
|
||||
# needed for multi-threaded programs (defaults to the value of CC
|
||||
# respectively CXX otherwise). (This is necessary on e.g. AIX to use the
|
||||
# special cc_r/CC_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also link it with them as well. e.g. you should link with
|
||||
# but also to link with them as well. For example, you might link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threads programs, you may wish to use these
|
||||
# If you are only building threaded programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
# CXX="$PTHREAD_CXX"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
|
||||
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
|
||||
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
||||
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
||||
|
@ -55,6 +59,7 @@
|
|||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
# Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
|
@ -67,7 +72,7 @@
|
|||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
|
@ -82,35 +87,41 @@
|
|||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 21
|
||||
#serial 31
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_PROG_SED])
|
||||
AC_LANG_PUSH([C])
|
||||
ax_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||
# requires special compiler flags (e.g. on Tru64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
|
||||
ax_pthread_save_CC="$CC"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
|
||||
AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||
AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
|
||||
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CC="$ax_pthread_save_CC"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
|
@ -118,12 +129,14 @@ fi
|
|||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
# Create a list of thread flags to try. Items with a "," contain both
|
||||
# C compiler flags (before ",") and linker flags (after ","). Other items
|
||||
# starting with a "-" are C compiler flags, and remaining items are
|
||||
# library names, except for "none" which indicates that we try without
|
||||
# any flags at all, and "pthread-config" which is a program returning
|
||||
# the flags for the Pth emulation library.
|
||||
|
||||
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
@ -132,82 +145,163 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt
|
|||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||
# -pthreads: Solaris/gcc
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
|
||||
# (Note: HP C rejects this with "bad form for `-t' option")
|
||||
# -pthreads: Solaris/gcc (Note: HP C also rejects)
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# doesn't hurt to check since this sometimes defines pthreads and
|
||||
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
|
||||
# is present but should not be used directly; and before -mthreads,
|
||||
# because the compiler interprets this as "-mt" + "-hreads")
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case ${host_os} in
|
||||
case $host_os in
|
||||
|
||||
freebsd*)
|
||||
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
|
||||
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
hpux*)
|
||||
|
||||
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
|
||||
# multi-threading and also sets -lpthread."
|
||||
|
||||
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
openedition*)
|
||||
|
||||
# IBM z/OS requires a feature-test macro to be defined in order to
|
||||
# enable POSIX threads at all, so give the user a hint if this is
|
||||
# not set. (We don't define these ourselves, as they can affect
|
||||
# other portions of the system API in unpredictable ways.)
|
||||
|
||||
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
|
||||
[
|
||||
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
|
||||
AX_PTHREAD_ZOS_MISSING
|
||||
# endif
|
||||
],
|
||||
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
|
||||
;;
|
||||
|
||||
solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
# tests will erroneously succeed. (N.B.: The stubs are missing
|
||||
# pthread_cleanup_push, or rather a function called by this macro,
|
||||
# so we could check for that, but who knows whether they'll stub
|
||||
# that too in a future libc.) So we'll check first for the
|
||||
# standard Solaris way of linking pthreads (-mt -lpthread).
|
||||
|
||||
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
darwin*)
|
||||
ax_pthread_flags="-pthread $ax_pthread_flags"
|
||||
ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Clang doesn't consider unrecognized options an error unless we specify
|
||||
# -Werror. We throw in some extra Clang-specific options to ensure that
|
||||
# this doesn't happen for GCC, which also accepts -Werror.
|
||||
# Are we compiling with Clang?
|
||||
|
||||
AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
|
||||
save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_extra_flags="-Werror"
|
||||
CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[ax_pthread_extra_flags=
|
||||
AC_MSG_RESULT([no])])
|
||||
CFLAGS="$save_CFLAGS"
|
||||
AC_CACHE_CHECK([whether $CC is Clang],
|
||||
[ax_cv_PTHREAD_CLANG],
|
||||
[ax_cv_PTHREAD_CLANG=no
|
||||
# Note that Autoconf sets GCC=yes for Clang as well as GCC
|
||||
if test "x$GCC" = "xyes"; then
|
||||
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
|
||||
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
|
||||
# if defined(__clang__) && defined(__llvm__)
|
||||
AX_PTHREAD_CC_IS_CLANG
|
||||
# endif
|
||||
],
|
||||
[ax_cv_PTHREAD_CLANG=yes])
|
||||
fi
|
||||
])
|
||||
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
|
||||
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
for flag in $ax_pthread_flags; do
|
||||
|
||||
case $flag in
|
||||
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
|
||||
|
||||
# Note that for GCC and Clang -pthread generally implies -lpthread,
|
||||
# except when -nostdlib is passed.
|
||||
# This is problematic using libtool to build C++ shared libraries with pthread:
|
||||
# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
|
||||
# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
|
||||
# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
|
||||
# To solve this, first try -pthread together with -lpthread for GCC
|
||||
|
||||
AS_IF([test "x$GCC" = "xyes"],
|
||||
[ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
|
||||
|
||||
# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
|
||||
|
||||
AS_IF([test "x$ax_pthread_clang" = "xyes"],
|
||||
[ax_pthread_flags="-pthread,-lpthread -pthread"])
|
||||
|
||||
|
||||
# The presence of a feature test macro requesting re-entrant function
|
||||
# definitions is, on some systems, a strong hint that pthreads support is
|
||||
# correctly enabled
|
||||
|
||||
case $host_os in
|
||||
darwin* | hpux* | linux* | osf* | solaris*)
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
;;
|
||||
|
||||
aix*)
|
||||
ax_pthread_check_macro="_THREAD_SAFE"
|
||||
;;
|
||||
|
||||
*)
|
||||
ax_pthread_check_macro="--"
|
||||
;;
|
||||
esac
|
||||
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
|
||||
[ax_pthread_check_cond=0],
|
||||
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
|
||||
|
||||
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
for ax_pthread_try_flag in $ax_pthread_flags; do
|
||||
|
||||
case $ax_pthread_try_flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
*,*)
|
||||
PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
|
||||
PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
|
||||
AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
PTHREAD_CFLAGS="$flag"
|
||||
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
|
||||
PTHREAD_CFLAGS="$ax_pthread_try_flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
|
||||
if test x"$ax_pthread_config" = xno; then continue; fi
|
||||
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
PTHREAD_LIBS="-l$flag"
|
||||
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
|
||||
PTHREAD_LIBS="-l$ax_pthread_try_flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
|
@ -218,8 +312,18 @@ for flag in $ax_pthread_flags; do
|
|||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
|
||||
static void routine(void *a) { *((int*)a) = 0; }
|
||||
# if $ax_pthread_check_cond
|
||||
# error "$ax_pthread_check_macro must be defined"
|
||||
# endif
|
||||
static void *some_global = NULL;
|
||||
static void routine(void *a)
|
||||
{
|
||||
/* To avoid any unused-parameter or
|
||||
unused-but-set-parameter warning. */
|
||||
some_global = a;
|
||||
}
|
||||
static void *start_routine(void *a) { return a; }],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
pthread_create(&th, 0, start_routine, 0);
|
||||
|
@ -227,101 +331,187 @@ for flag in $ax_pthread_flags; do
|
|||
pthread_attr_init(&attr);
|
||||
pthread_cleanup_push(routine, 0);
|
||||
pthread_cleanup_pop(0) /* ; */])],
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
break;
|
||||
fi
|
||||
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Clang needs special handling, because older versions handle the -pthread
|
||||
# option in a rather... idiosyncratic way
|
||||
|
||||
if test "x$ax_pthread_clang" = "xyes"; then
|
||||
|
||||
# Clang takes -pthread; it has never supported any other flag
|
||||
|
||||
# (Note 1: This will need to be revisited if a system that Clang
|
||||
# supports has POSIX threads in a separate library. This tends not
|
||||
# to be the way of modern systems, but it's conceivable.)
|
||||
|
||||
# (Note 2: On some systems, notably Darwin, -pthread is not needed
|
||||
# to get POSIX threads support; the API is always present and
|
||||
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
|
||||
# -pthread does define _REENTRANT, and while the Darwin headers
|
||||
# ignore this macro, third-party headers might not.)
|
||||
|
||||
# However, older versions of Clang make a point of warning the user
|
||||
# that, in an invocation where only linking and no compilation is
|
||||
# taking place, the -pthread option has no effect ("argument unused
|
||||
# during compilation"). They expect -pthread to be passed in only
|
||||
# when source code is being compiled.
|
||||
#
|
||||
# Problem is, this is at odds with the way Automake and most other
|
||||
# C build frameworks function, which is that the same flags used in
|
||||
# compilation (CFLAGS) are also used in linking. Many systems
|
||||
# supported by AX_PTHREAD require exactly this for POSIX threads
|
||||
# support, and in fact it is often not straightforward to specify a
|
||||
# flag that is used only in the compilation phase and not in
|
||||
# linking. Such a scenario is extremely rare in practice.
|
||||
#
|
||||
# Even though use of the -pthread flag in linking would only print
|
||||
# a warning, this can be a nuisance for well-run software projects
|
||||
# that build with -Werror. So if the active version of Clang has
|
||||
# this misfeature, we search for an option to squash it.
|
||||
|
||||
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
|
||||
# Create an alternate version of $ac_link that compiles and
|
||||
# links in two steps (.c -> .o, .o -> exe) instead of one
|
||||
# (.c -> exe), because the warning occurs only in the second
|
||||
# step
|
||||
ax_pthread_save_ac_link="$ac_link"
|
||||
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
|
||||
ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
|
||||
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
|
||||
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
|
||||
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[ac_link="$ax_pthread_2step_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[break])
|
||||
])
|
||||
done
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
|
||||
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
|
||||
])
|
||||
|
||||
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
|
||||
no | unknown) ;;
|
||||
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
|
||||
esac
|
||||
|
||||
fi # $ax_pthread_clang = yes
|
||||
|
||||
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
attr_name=unknown
|
||||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $attr; return attr /* ; */])],
|
||||
[attr_name=$attr; break],
|
||||
[])
|
||||
done
|
||||
AC_MSG_RESULT([$attr_name])
|
||||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
AC_CACHE_CHECK([for joinable pthread attribute],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
|
||||
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $ax_pthread_attr; return attr /* ; */])],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
|
||||
[])
|
||||
done
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
|
||||
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
|
||||
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
|
||||
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
|
||||
[$ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
ax_pthread_joinable_attr_defined=yes
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
case ${host_os} in
|
||||
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
|
||||
osf* | hpux*) flag="-D_REENTRANT";;
|
||||
solaris*)
|
||||
if test "$GCC" = "yes"; then
|
||||
flag="-D_REENTRANT"
|
||||
else
|
||||
# TODO: What about Clang on Solaris?
|
||||
flag="-mt -D_REENTRANT"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$flag])
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
AC_CACHE_CHECK([whether more special flags are required for pthreads],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
|
||||
case $host_os in
|
||||
solaris*)
|
||||
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
|
||||
;;
|
||||
esac
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
|
||||
test "x$ax_pthread_special_flags_added" != "xyes"],
|
||||
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
|
||||
ax_pthread_special_flags_added=yes])
|
||||
|
||||
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;
|
||||
return i;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
|
||||
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
|
||||
ax_pthread_prio_inherit_defined=yes
|
||||
])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
# More AIX lossage: compile with *_r variant
|
||||
if test "x$GCC" != xyes; then
|
||||
if test "x$GCC" != "xyes"; then
|
||||
case $host_os in
|
||||
aix*)
|
||||
AS_CASE(["x/$CC"],
|
||||
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
||||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
|
||||
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
|
||||
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
||||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[
|
||||
AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
|
||||
AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
|
||||
],
|
||||
[
|
||||
AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
|
||||
AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
|
||||
]
|
||||
)
|
||||
])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
|
||||
test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
|
||||
|
||||
AC_SUBST([PTHREAD_LIBS])
|
||||
AC_SUBST([PTHREAD_CFLAGS])
|
||||
AC_SUBST([PTHREAD_CC])
|
||||
AC_SUBST([PTHREAD_CXX])
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$ax_pthread_ok" = xyes; then
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
|
||||
:
|
||||
else
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/mesh.h"
|
||||
#include "services/modstack.h"
|
||||
#include "validator/val_neg.h"
|
||||
#include "validator/val_secalgo.h"
|
||||
#include "iterator/iter_utils.h"
|
||||
|
@ -265,15 +267,6 @@ cachedb_init(struct module_env* env, int id)
|
|||
return 0;
|
||||
}
|
||||
cachedb_env->enabled = 1;
|
||||
if(env->cfg->serve_expired && env->cfg->serve_expired_reply_ttl)
|
||||
log_warn(
|
||||
"cachedb: serve-expired-reply-ttl is set but not working for data "
|
||||
"originating from the external cache; 0 TTL is used for those.");
|
||||
if(env->cfg->serve_expired && env->cfg->serve_expired_client_timeout)
|
||||
log_warn(
|
||||
"cachedb: serve-expired-client-timeout is set but not working for "
|
||||
"data originating from the external cache; expired data are used "
|
||||
"in the reply without first trying to refresh the data.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -511,9 +504,38 @@ adjust_msg_ttl(struct dns_msg* msg, time_t adjust)
|
|||
}
|
||||
}
|
||||
|
||||
/* Set the TTL of the given RRset to fixed value. */
|
||||
static void
|
||||
packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl)
|
||||
{
|
||||
size_t i;
|
||||
size_t total = data->count + data->rrsig_count;
|
||||
data->ttl = ttl;
|
||||
for(i=0; i<total; i++) {
|
||||
data->rr_ttl[i] = ttl;
|
||||
}
|
||||
data->ttl_add = 0;
|
||||
}
|
||||
|
||||
/* Set the TTL of a DNS message and its RRs by to a fixed value. */
|
||||
static void
|
||||
set_msg_ttl(struct dns_msg* msg, time_t ttl)
|
||||
{
|
||||
size_t i;
|
||||
msg->rep->ttl = ttl;
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
|
||||
|
||||
for(i=0; i<msg->rep->rrset_count; i++) {
|
||||
packed_rrset_ttl_set((struct packed_rrset_data*)msg->
|
||||
rep->rrsets[i]->entry.data, ttl);
|
||||
}
|
||||
}
|
||||
|
||||
/** convert dns message in buffer to return_msg */
|
||||
static int
|
||||
parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
|
||||
int* msg_expired)
|
||||
{
|
||||
struct msg_parse* prs;
|
||||
struct edns_data edns;
|
||||
|
@ -583,6 +605,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
|||
adjust = *qstate->env->now - (time_t)timestamp;
|
||||
if(qstate->return_msg->rep->ttl < adjust) {
|
||||
verbose(VERB_ALGO, "cachedb msg expired");
|
||||
*msg_expired = 1;
|
||||
/* If serve-expired is enabled, we still use an expired message
|
||||
* setting the TTL to 0. */
|
||||
if(!qstate->env->cfg->serve_expired ||
|
||||
|
@ -605,6 +628,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
|||
* 'now' should be redundant given how these values were calculated,
|
||||
* but we check it just in case as does good_expiry_and_qinfo(). */
|
||||
if(qstate->env->cfg->serve_expired &&
|
||||
!qstate->env->cfg->serve_expired_client_timeout &&
|
||||
(adjust == -1 || (time_t)expiry < *qstate->env->now)) {
|
||||
qstate->need_refetch = 1;
|
||||
}
|
||||
|
@ -617,7 +641,8 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
|||
* return true if lookup was successful.
|
||||
*/
|
||||
static int
|
||||
cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie)
|
||||
cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie,
|
||||
int* msg_expired)
|
||||
{
|
||||
char key[(CACHEDB_HASHSIZE/8)*2+1];
|
||||
calc_hash(qstate, key, sizeof(key));
|
||||
|
@ -634,7 +659,7 @@ cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie)
|
|||
}
|
||||
|
||||
/* parse dns message into return_msg */
|
||||
if( !parse_data(qstate, qstate->env->scratch_buffer) ) {
|
||||
if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired) ) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -666,6 +691,7 @@ cachedb_extcache_store(struct module_qstate* qstate, struct cachedb_env* ie)
|
|||
static int
|
||||
cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde)
|
||||
{
|
||||
uint8_t dpname_storage[LDNS_MAX_DOMAINLEN+1];
|
||||
uint8_t* dpname=NULL;
|
||||
size_t dpnamelen=0;
|
||||
struct dns_msg* msg;
|
||||
|
@ -674,7 +700,7 @@ cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde)
|
|||
return 0;
|
||||
}
|
||||
if(iter_stub_fwd_no_cache(qstate, &qstate->qinfo,
|
||||
&dpname, &dpnamelen))
|
||||
&dpname, &dpnamelen, dpname_storage, sizeof(dpname_storage)))
|
||||
return 0; /* no cache for these queries */
|
||||
msg = dns_cache_lookup(qstate->env, qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len, qstate->qinfo.qtype,
|
||||
|
@ -705,17 +731,39 @@ cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde)
|
|||
* Store query into the internal cache of unbound.
|
||||
*/
|
||||
static void
|
||||
cachedb_intcache_store(struct module_qstate* qstate)
|
||||
cachedb_intcache_store(struct module_qstate* qstate, int msg_expired)
|
||||
{
|
||||
uint32_t store_flags = qstate->query_flags;
|
||||
int serve_expired = qstate->env->cfg->serve_expired;
|
||||
|
||||
if(qstate->env->cfg->serve_expired)
|
||||
store_flags |= DNSCACHE_STORE_ZEROTTL;
|
||||
if(!qstate->return_msg)
|
||||
return;
|
||||
if(serve_expired && msg_expired) {
|
||||
/* Set TTLs to a value such that value + *env->now is
|
||||
* going to be now-3 seconds. Making it expired
|
||||
* in the cache. */
|
||||
set_msg_ttl(qstate->return_msg, (time_t)-3);
|
||||
}
|
||||
(void)dns_cache_store(qstate->env, &qstate->qinfo,
|
||||
qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0,
|
||||
qstate->region, store_flags, qstate->qstarttime);
|
||||
if(serve_expired && msg_expired) {
|
||||
if(qstate->env->cfg->serve_expired_client_timeout) {
|
||||
/* No expired response from the query state, the
|
||||
* query resolution needs to continue and it can
|
||||
* pick up the expired result after the timer out
|
||||
* of cache. */
|
||||
return;
|
||||
}
|
||||
/* set TTLs to zero again */
|
||||
adjust_msg_ttl(qstate->return_msg, -1);
|
||||
/* Send serve expired responses based on the cachedb
|
||||
* returned message, that was just stored in the cache.
|
||||
* It can then continue to work on this query. */
|
||||
mesh_respond_serve_expired(qstate->mesh_info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -731,6 +779,7 @@ cachedb_handle_query(struct module_qstate* qstate,
|
|||
struct cachedb_qstate* ATTR_UNUSED(iq),
|
||||
struct cachedb_env* ie, int id)
|
||||
{
|
||||
int msg_expired = 0;
|
||||
qstate->is_cachedb_answer = 0;
|
||||
/* check if we are enabled, and skip if so */
|
||||
if(!ie->enabled) {
|
||||
|
@ -765,20 +814,28 @@ cachedb_handle_query(struct module_qstate* qstate,
|
|||
}
|
||||
|
||||
/* ask backend cache to see if we have data */
|
||||
if(cachedb_extcache_lookup(qstate, ie)) {
|
||||
if(cachedb_extcache_lookup(qstate, ie, &msg_expired)) {
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg(ie->backend->name,
|
||||
&qstate->return_msg->qinfo,
|
||||
qstate->return_msg->rep);
|
||||
/* store this result in internal cache */
|
||||
cachedb_intcache_store(qstate);
|
||||
cachedb_intcache_store(qstate, msg_expired);
|
||||
/* In case we have expired data but there is a client timer for expired
|
||||
* answers, pass execution to next module in order to try updating the
|
||||
* data first.
|
||||
* TODO: this needs revisit. The expired data stored from cachedb has
|
||||
* 0 TTL which is picked up by iterator later when looking in the cache.
|
||||
* Document that ext cachedb does not work properly with
|
||||
* serve_stale_reply_ttl yet. */
|
||||
*/
|
||||
if(qstate->env->cfg->serve_expired && msg_expired) {
|
||||
qstate->return_msg = NULL;
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
/* The expired reply is sent with
|
||||
* mesh_respond_serve_expired, and so
|
||||
* the need_refetch is not used. */
|
||||
qstate->need_refetch = 0;
|
||||
return;
|
||||
}
|
||||
if(qstate->need_refetch && qstate->serve_expired_data &&
|
||||
qstate->serve_expired_data->timer) {
|
||||
qstate->return_msg = NULL;
|
||||
|
@ -791,6 +848,14 @@ cachedb_handle_query(struct module_qstate* qstate,
|
|||
return;
|
||||
}
|
||||
|
||||
if(qstate->serve_expired_data &&
|
||||
qstate->env->cfg->cachedb_check_when_serve_expired &&
|
||||
!qstate->env->cfg->serve_expired_client_timeout) {
|
||||
/* Reply with expired data if any to client, because cachedb
|
||||
* also has no useful, current data */
|
||||
mesh_respond_serve_expired(qstate->mesh_info);
|
||||
}
|
||||
|
||||
/* no cache fetches */
|
||||
/* pass request to next module */
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
|
@ -923,4 +988,36 @@ cachedb_get_funcblock(void)
|
|||
{
|
||||
return &cachedb_block;
|
||||
}
|
||||
|
||||
int
|
||||
cachedb_is_enabled(struct module_stack* mods, struct module_env* env)
|
||||
{
|
||||
struct cachedb_env* ie;
|
||||
int id = modstack_find(mods, "cachedb");
|
||||
if(id == -1)
|
||||
return 0;
|
||||
ie = (struct cachedb_env*)env->modinfo[id];
|
||||
if(ie && ie->enabled)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cachedb_msg_remove(struct module_qstate* qstate)
|
||||
{
|
||||
char key[(CACHEDB_HASHSIZE/8)*2+1];
|
||||
int id = modstack_find(qstate->env->modstack, "cachedb");
|
||||
struct cachedb_env* ie = (struct cachedb_env*)qstate->env->modinfo[id];
|
||||
|
||||
log_query_info(VERB_ALGO, "cachedb msg remove", &qstate->qinfo);
|
||||
calc_hash(qstate, key, sizeof(key));
|
||||
sldns_buffer_clear(qstate->env->scratch_buffer);
|
||||
sldns_buffer_write_u32(qstate->env->scratch_buffer, 0);
|
||||
sldns_buffer_flip(qstate->env->scratch_buffer);
|
||||
|
||||
/* call backend */
|
||||
(*ie->backend->store)(qstate->env, ie, key,
|
||||
sldns_buffer_begin(qstate->env->scratch_buffer),
|
||||
sldns_buffer_limit(qstate->env->scratch_buffer),
|
||||
0);
|
||||
}
|
||||
#endif /* USE_CACHEDB */
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
*/
|
||||
#include "util/module.h"
|
||||
struct cachedb_backend;
|
||||
struct module_stack;
|
||||
|
||||
/**
|
||||
* The global variable environment contents for the cachedb
|
||||
|
@ -110,3 +111,18 @@ size_t cachedb_get_mem(struct module_env* env, int id);
|
|||
*/
|
||||
struct module_func_block* cachedb_get_funcblock(void);
|
||||
|
||||
/**
|
||||
* See if the cachedb is enabled.
|
||||
* @param mods: module stack. It finds the cachedb module environment.
|
||||
* @param env: module environment.
|
||||
* @return true if exists and enabled.
|
||||
*/
|
||||
int cachedb_is_enabled(struct module_stack* mods, struct module_env* env);
|
||||
|
||||
/**
|
||||
* Remove a message from the global cache. Because edns subnet has a more
|
||||
* specific entry, and if not removed when everything expires, the global
|
||||
* entry is used, instead of a fresh lookup of the edns subnet entry.
|
||||
* @param qstate: query state.
|
||||
*/
|
||||
void cachedb_msg_remove(struct module_qstate* qstate);
|
||||
|
|
|
@ -379,8 +379,8 @@
|
|||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
/* Define to 1 if you have the <minix/config.h> header file. */
|
||||
#undef HAVE_MINIX_CONFIG_H
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
@ -587,6 +587,9 @@
|
|||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
|
@ -689,6 +692,9 @@
|
|||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
#undef HAVE_VFORK_H
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
#undef HAVE_WCHAR_H
|
||||
|
||||
/* Define to 1 if you have the <windows.h> header file. */
|
||||
#undef HAVE_WINDOWS_H
|
||||
|
||||
|
@ -830,7 +836,9 @@
|
|||
/* Define to 1 if libsodium supports sodium_set_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. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* use default strptime. */
|
||||
|
@ -926,21 +934,87 @@
|
|||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on macOS. */
|
||||
#ifndef _DARWIN_C_SOURCE
|
||||
# undef _DARWIN_C_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#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
|
||||
# undef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
#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
|
||||
# undef _NETBSD_SOURCE
|
||||
#endif
|
||||
/* Enable OpenBSD compatibility extensions on NetBSD.
|
||||
Oddly enough, this does nothing on OpenBSD. */
|
||||
#ifndef _OPENBSD_SOURCE
|
||||
# undef _OPENBSD_SOURCE
|
||||
#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
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
|
||||
#ifndef __STDC_WANT_LIB_EXT2__
|
||||
# undef __STDC_WANT_LIB_EXT2__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC 24747:2009. */
|
||||
#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
# undef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
/* Enable X/Open extensions. Define to 500 only if necessary
|
||||
to make mbstate_t available. */
|
||||
#ifndef _XOPEN_SOURCE
|
||||
# undef _XOPEN_SOURCE
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -966,11 +1040,6 @@
|
|||
`char[]'. */
|
||||
#undef YYTEXT_POINTER
|
||||
|
||||
/* 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. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
|
@ -980,19 +1049,9 @@
|
|||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
#undef _MINIX
|
||||
|
||||
/* Enable for compile on Minix */
|
||||
#undef _NETBSD_SOURCE
|
||||
|
||||
/* 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
|
||||
compiled for windows. */
|
||||
#undef __USE_MINGW_ANSI_STDIO
|
||||
|
@ -1033,7 +1092,7 @@
|
|||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
#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
|
||||
|
||||
/* Define to 'int' if not defined */
|
||||
|
|
12608
usr.sbin/unbound/configure
vendored
12608
usr.sbin/unbound/configure
vendored
File diff suppressed because it is too large
Load diff
|
@ -4,21 +4,21 @@ AC_PREREQ([2.56])
|
|||
sinclude(acx_nlnetlabs.m4)
|
||||
sinclude(ax_pthread.m4)
|
||||
sinclude(acx_python.m4)
|
||||
sinclude(ac_pkg_swig.m4)
|
||||
sinclude(ax_pkg_swig.m4)
|
||||
sinclude(dnstap/dnstap.m4)
|
||||
sinclude(dnscrypt/dnscrypt.m4)
|
||||
|
||||
# must be numbers. ac_defun because of later processing
|
||||
m4_define([VERSION_MAJOR],[1])
|
||||
m4_define([VERSION_MINOR],[19])
|
||||
m4_define([VERSION_MICRO],[3])
|
||||
m4_define([VERSION_MINOR],[20])
|
||||
m4_define([VERSION_MICRO],[0])
|
||||
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound])
|
||||
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
|
||||
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
|
||||
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
|
||||
|
||||
LIBUNBOUND_CURRENT=9
|
||||
LIBUNBOUND_REVISION=26
|
||||
LIBUNBOUND_REVISION=27
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
|
@ -112,6 +112,7 @@ LIBUNBOUND_AGE=1
|
|||
# 1.19.1 had 9:24:1
|
||||
# 1.19.2 had 9:25:1
|
||||
# 1.19.3 had 9:26:1
|
||||
# 1.20.0 had 9:27:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
|
@ -273,6 +274,9 @@ AC_DEFINE(WINVER, 0x0502, [the version of the windows API enabled])
|
|||
ACX_RSRC_VERSION(wnvs)
|
||||
AC_DEFINE_UNQUOTED(RSRC_PACKAGE_VERSION, [$wnvs], [version number for resource files])
|
||||
|
||||
# Check for 'grep -e' program, here, since ACX_CHECK_FLTO needs that.
|
||||
AC_PROG_GREP
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_LANG([C])
|
||||
|
@ -795,9 +799,9 @@ if test x_$ub_test_python != x_no; then
|
|||
ub_have_swig=no
|
||||
AC_ARG_ENABLE(swig-version-check, AS_HELP_STRING([--disable-swig-version-check],[Disable swig version check to build python modules with older swig even though that is unreliable]))
|
||||
if test "$enable_swig_version_check" = "yes"; then
|
||||
AC_PROG_SWIG(2.0.1)
|
||||
AX_PKG_SWIG(2.0.1)
|
||||
else
|
||||
AC_PROG_SWIG
|
||||
AX_PKG_SWIG
|
||||
fi
|
||||
AC_MSG_CHECKING(SWIG)
|
||||
if test ! -x "$SWIG"; then
|
||||
|
|
|
@ -839,6 +839,7 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
|
|||
char b[260];
|
||||
struct query_info qinfo;
|
||||
struct iter_hints_stub* stub;
|
||||
int nolock = 0;
|
||||
regional_free_all(region);
|
||||
qinfo.qname = nm;
|
||||
qinfo.qname_len = nmlen;
|
||||
|
@ -851,12 +852,15 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
|
|||
"of %s\n", b))
|
||||
return 0;
|
||||
|
||||
dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass);
|
||||
dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass, nolock);
|
||||
if(dp) {
|
||||
if(!ssl_printf(ssl, "forwarding request:\n"))
|
||||
if(!ssl_printf(ssl, "forwarding request:\n")) {
|
||||
lock_rw_unlock(&worker->env.fwds->lock);
|
||||
return 0;
|
||||
}
|
||||
print_dp_main(ssl, dp, NULL);
|
||||
print_dp_details(ssl, worker, dp);
|
||||
lock_rw_unlock(&worker->env.fwds->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -894,19 +898,24 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
|
|||
}
|
||||
}
|
||||
stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass,
|
||||
dp);
|
||||
dp, nolock);
|
||||
if(stub) {
|
||||
if(stub->noprime) {
|
||||
if(!ssl_printf(ssl, "The noprime stub servers "
|
||||
"are used:\n"))
|
||||
"are used:\n")) {
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if(!ssl_printf(ssl, "The stub is primed "
|
||||
"with servers:\n"))
|
||||
"with servers:\n")) {
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
print_dp_main(ssl, stub->dp, NULL);
|
||||
print_dp_details(ssl, worker, stub->dp);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
} else {
|
||||
print_dp_main(ssl, dp, msg);
|
||||
print_dp_details(ssl, worker, dp);
|
||||
|
|
|
@ -91,6 +91,8 @@
|
|||
#include "util/net_help.h"
|
||||
#include "sldns/keyraw.h"
|
||||
#include "respip/respip.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_SYSTEMD
|
||||
|
@ -99,6 +101,9 @@
|
|||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef USE_CACHEDB
|
||||
#include "cachedb/cachedb.h"
|
||||
#endif
|
||||
|
||||
/** How many quit requests happened. */
|
||||
static int sig_record_quit = 0;
|
||||
|
@ -260,6 +265,7 @@ daemon_init(void)
|
|||
free(daemon);
|
||||
return NULL;
|
||||
}
|
||||
daemon->env->modstack = &daemon->mods;
|
||||
/* init edns_known_options */
|
||||
if(!edns_known_options_init(daemon->env)) {
|
||||
free(daemon->env);
|
||||
|
@ -321,17 +327,15 @@ static int setup_acl_for_ports(struct acl_list* list,
|
|||
struct listen_port* port_list)
|
||||
{
|
||||
struct acl_addr* acl_node;
|
||||
struct addrinfo* addr;
|
||||
for(; port_list; port_list=port_list->next) {
|
||||
if(!port_list->socket) {
|
||||
/* This is mainly for testbound where port_list is
|
||||
* empty. */
|
||||
continue;
|
||||
}
|
||||
addr = port_list->socket->addr;
|
||||
if(!(acl_node = acl_interface_insert(list,
|
||||
(struct sockaddr_storage*)addr->ai_addr,
|
||||
(socklen_t)addr->ai_addrlen,
|
||||
(struct sockaddr_storage*)port_list->socket->addr,
|
||||
port_list->socket->addrlen,
|
||||
acl_refuse))) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -716,6 +720,12 @@ daemon_fork(struct daemon* daemon)
|
|||
fatal_exit("Could not create local zones: out of memory");
|
||||
if(!local_zones_apply_cfg(daemon->local_zones, daemon->cfg))
|
||||
fatal_exit("Could not set up local zones");
|
||||
if(!(daemon->env->fwds = forwards_create()) ||
|
||||
!forwards_apply_cfg(daemon->env->fwds, daemon->cfg))
|
||||
fatal_exit("Could not set forward zones");
|
||||
if(!(daemon->env->hints = hints_create()) ||
|
||||
!hints_apply_cfg(daemon->env->hints, daemon->cfg))
|
||||
fatal_exit("Could not set root or stub hints");
|
||||
|
||||
/* process raw response-ip configuration data */
|
||||
if(!(daemon->respip_set = respip_set_create()))
|
||||
|
@ -740,6 +750,10 @@ daemon_fork(struct daemon* daemon)
|
|||
if(!edns_strings_apply_cfg(daemon->env->edns_strings, daemon->cfg))
|
||||
fatal_exit("Could not set up EDNS strings");
|
||||
|
||||
#ifdef USE_CACHEDB
|
||||
daemon->env->cachedb_enabled = cachedb_is_enabled(&daemon->mods,
|
||||
daemon->env);
|
||||
#endif
|
||||
/* response-ip-xxx options don't work as expected without the respip
|
||||
* module. To avoid run-time operational surprise we reject such
|
||||
* configuration. */
|
||||
|
@ -832,6 +846,10 @@ daemon_cleanup(struct daemon* daemon)
|
|||
slabhash_clear(daemon->env->msg_cache);
|
||||
}
|
||||
daemon->old_num = daemon->num; /* save the current num */
|
||||
forwards_delete(daemon->env->fwds);
|
||||
daemon->env->fwds = NULL;
|
||||
hints_delete(daemon->env->hints);
|
||||
daemon->env->hints = NULL;
|
||||
local_zones_delete(daemon->local_zones);
|
||||
daemon->local_zones = NULL;
|
||||
respip_set_delete(daemon->respip_set);
|
||||
|
|
|
@ -1992,12 +1992,19 @@ static int
|
|||
print_root_fwds(RES* ssl, struct iter_forwards* fwds, uint8_t* root)
|
||||
{
|
||||
struct delegpt* dp;
|
||||
dp = forwards_lookup(fwds, root, LDNS_RR_CLASS_IN);
|
||||
if(!dp)
|
||||
int nolock = 0;
|
||||
dp = forwards_lookup(fwds, root, LDNS_RR_CLASS_IN, nolock);
|
||||
if(!dp) {
|
||||
return ssl_printf(ssl, "off (using root hints)\n");
|
||||
}
|
||||
/* if dp is returned it must be the root */
|
||||
log_assert(query_dname_compare(dp->name, root)==0);
|
||||
return ssl_print_name_dp(ssl, NULL, root, LDNS_RR_CLASS_IN, dp);
|
||||
if(!ssl_print_name_dp(ssl, NULL, root, LDNS_RR_CLASS_IN, dp)) {
|
||||
lock_rw_unlock(&fwds->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&fwds->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** parse args into delegpt */
|
||||
|
@ -2069,6 +2076,7 @@ do_forward(RES* ssl, struct worker* worker, char* args)
|
|||
{
|
||||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
uint8_t* root = (uint8_t*)"\000";
|
||||
int nolock = 0;
|
||||
if(!fwd) {
|
||||
(void)ssl_printf(ssl, "error: structure not allocated\n");
|
||||
return;
|
||||
|
@ -2082,12 +2090,12 @@ do_forward(RES* ssl, struct worker* worker, char* args)
|
|||
/* delete all the existing queries first */
|
||||
mesh_delete_all(worker->env.mesh);
|
||||
if(strcmp(args, "off") == 0) {
|
||||
forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, root);
|
||||
forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, root, nolock);
|
||||
} else {
|
||||
struct delegpt* dp;
|
||||
if(!(dp = parse_delegpt(ssl, args, root)))
|
||||
return;
|
||||
if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) {
|
||||
if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp, nolock)) {
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
@ -2097,7 +2105,7 @@ do_forward(RES* ssl, struct worker* worker, char* args)
|
|||
|
||||
static int
|
||||
parse_fs_args(RES* ssl, char* args, uint8_t** nm, struct delegpt** dp,
|
||||
int* insecure, int* prime)
|
||||
int* insecure, int* prime, int* tls)
|
||||
{
|
||||
char* zonename;
|
||||
char* rest;
|
||||
|
@ -2112,6 +2120,8 @@ parse_fs_args(RES* ssl, char* args, uint8_t** nm, struct delegpt** dp,
|
|||
*insecure = 1;
|
||||
else if(*args == 'p' && prime)
|
||||
*prime = 1;
|
||||
else if(*args == 't' && tls)
|
||||
*tls = 1;
|
||||
else {
|
||||
(void)ssl_printf(ssl, "error: unknown option %s\n", args);
|
||||
return 0;
|
||||
|
@ -2144,25 +2154,33 @@ static void
|
|||
do_forward_add(RES* ssl, struct worker* worker, char* args)
|
||||
{
|
||||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
int insecure = 0;
|
||||
int insecure = 0, tls = 0;
|
||||
uint8_t* nm = NULL;
|
||||
struct delegpt* dp = NULL;
|
||||
if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, NULL))
|
||||
int nolock = 1;
|
||||
if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, NULL, &tls))
|
||||
return;
|
||||
if(tls)
|
||||
dp->ssl_upstream = 1;
|
||||
/* prelock forwarders for atomic operation with anchors */
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
if(insecure && worker->env.anchors) {
|
||||
if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN,
|
||||
nm)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
delegpt_free_mlc(dp);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) {
|
||||
if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp, nolock)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
}
|
||||
|
@ -2174,12 +2192,16 @@ do_forward_remove(RES* ssl, struct worker* worker, char* args)
|
|||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
int insecure = 0;
|
||||
uint8_t* nm = NULL;
|
||||
if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL))
|
||||
int nolock = 1;
|
||||
if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL, NULL))
|
||||
return;
|
||||
/* prelock forwarders for atomic operation with anchors */
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
if(insecure && worker->env.anchors)
|
||||
anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN,
|
||||
nm);
|
||||
forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, nm);
|
||||
forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, nm, nolock);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
}
|
||||
|
@ -2189,38 +2211,53 @@ static void
|
|||
do_stub_add(RES* ssl, struct worker* worker, char* args)
|
||||
{
|
||||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
int insecure = 0, prime = 0;
|
||||
int insecure = 0, prime = 0, tls = 0;
|
||||
uint8_t* nm = NULL;
|
||||
struct delegpt* dp = NULL;
|
||||
if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, &prime))
|
||||
int nolock = 1;
|
||||
if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, &prime, &tls))
|
||||
return;
|
||||
if(tls)
|
||||
dp->ssl_upstream = 1;
|
||||
/* prelock forwarders and hints for atomic operation with anchors */
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
lock_rw_wrlock(&worker->env.hints->lock);
|
||||
if(insecure && worker->env.anchors) {
|
||||
if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN,
|
||||
nm)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
delegpt_free_mlc(dp);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!forwards_add_stub_hole(fwd, LDNS_RR_CLASS_IN, nm)) {
|
||||
if(!forwards_add_stub_hole(fwd, LDNS_RR_CLASS_IN, nm, nolock)) {
|
||||
if(insecure && worker->env.anchors)
|
||||
anchors_delete_insecure(worker->env.anchors,
|
||||
LDNS_RR_CLASS_IN, nm);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
delegpt_free_mlc(dp);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
if(!hints_add_stub(worker->env.hints, LDNS_RR_CLASS_IN, dp, !prime)) {
|
||||
if(!hints_add_stub(worker->env.hints, LDNS_RR_CLASS_IN, dp, !prime,
|
||||
nolock)) {
|
||||
(void)ssl_printf(ssl, "error out of memory\n");
|
||||
forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm);
|
||||
forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm, nolock);
|
||||
if(insecure && worker->env.anchors)
|
||||
anchors_delete_insecure(worker->env.anchors,
|
||||
LDNS_RR_CLASS_IN, nm);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
}
|
||||
|
@ -2232,13 +2269,19 @@ do_stub_remove(RES* ssl, struct worker* worker, char* args)
|
|||
struct iter_forwards* fwd = worker->env.fwds;
|
||||
int insecure = 0;
|
||||
uint8_t* nm = NULL;
|
||||
if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL))
|
||||
int nolock = 1;
|
||||
if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL, NULL))
|
||||
return;
|
||||
/* prelock forwarders and hints for atomic operation with anchors */
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
lock_rw_wrlock(&worker->env.hints->lock);
|
||||
if(insecure && worker->env.anchors)
|
||||
anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN,
|
||||
nm);
|
||||
forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm);
|
||||
hints_delete_stub(worker->env.hints, LDNS_RR_CLASS_IN, nm);
|
||||
forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm, nolock);
|
||||
hints_delete_stub(worker->env.hints, LDNS_RR_CLASS_IN, nm, nolock);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
free(nm);
|
||||
send_ok(ssl);
|
||||
}
|
||||
|
@ -2667,6 +2710,7 @@ do_list_forwards(RES* ssl, struct worker* worker)
|
|||
struct iter_forward_zone* z;
|
||||
struct trust_anchor* a;
|
||||
int insecure;
|
||||
lock_rw_rdlock(&fwds->lock);
|
||||
RBTREE_FOR(z, struct iter_forward_zone*, fwds->tree) {
|
||||
if(!z->dp) continue; /* skip empty marker for stub */
|
||||
|
||||
|
@ -2681,9 +2725,12 @@ do_list_forwards(RES* ssl, struct worker* worker)
|
|||
}
|
||||
|
||||
if(!ssl_print_name_dp(ssl, (insecure?"forward +i":"forward"),
|
||||
z->name, z->dclass, z->dp))
|
||||
z->name, z->dclass, z->dp)) {
|
||||
lock_rw_unlock(&fwds->lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
lock_rw_unlock(&fwds->lock);
|
||||
}
|
||||
|
||||
/** do the list_stubs command */
|
||||
|
@ -2694,6 +2741,7 @@ do_list_stubs(RES* ssl, struct worker* worker)
|
|||
struct trust_anchor* a;
|
||||
int insecure;
|
||||
char str[32];
|
||||
lock_rw_rdlock(&worker->env.hints->lock);
|
||||
RBTREE_FOR(z, struct iter_hints_stub*, &worker->env.hints->tree) {
|
||||
|
||||
/* see if it is insecure */
|
||||
|
@ -2709,9 +2757,12 @@ do_list_stubs(RES* ssl, struct worker* worker)
|
|||
snprintf(str, sizeof(str), "stub %sprime%s",
|
||||
(z->noprime?"no":""), (insecure?" +i":""));
|
||||
if(!ssl_print_name_dp(ssl, str, z->node.name,
|
||||
z->node.dclass, z->dp))
|
||||
z->node.dclass, z->dp)) {
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
lock_rw_unlock(&worker->env.hints->lock);
|
||||
}
|
||||
|
||||
/** do the list_auth_zones command */
|
||||
|
@ -3071,26 +3122,6 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
|
|||
} else if(cmdcmp(p, "auth_zone_transfer", 18)) {
|
||||
do_auth_zone_transfer(ssl, worker, skipwhite(p+18));
|
||||
return;
|
||||
} else if(cmdcmp(p, "stub_add", 8)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_stub_add(ssl, worker, skipwhite(p+8));
|
||||
return;
|
||||
} else if(cmdcmp(p, "stub_remove", 11)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_stub_remove(ssl, worker, skipwhite(p+11));
|
||||
return;
|
||||
} else if(cmdcmp(p, "forward_add", 11)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_forward_add(ssl, worker, skipwhite(p+11));
|
||||
return;
|
||||
} else if(cmdcmp(p, "forward_remove", 14)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_forward_remove(ssl, worker, skipwhite(p+14));
|
||||
return;
|
||||
} else if(cmdcmp(p, "insecure_add", 12)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
|
@ -3101,11 +3132,6 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
|
|||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_insecure_remove(ssl, worker, skipwhite(p+15));
|
||||
return;
|
||||
} else if(cmdcmp(p, "forward", 7)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_forward(ssl, worker, skipwhite(p+7));
|
||||
return;
|
||||
} else if(cmdcmp(p, "flush_stats", 11)) {
|
||||
/* must always distribute this cmd */
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
|
@ -3147,6 +3173,16 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
|
|||
do_data_add(ssl, worker->daemon->local_zones, skipwhite(p+10));
|
||||
} else if(cmdcmp(p, "local_datas", 11)) {
|
||||
do_datas_add(ssl, worker->daemon->local_zones);
|
||||
} else if(cmdcmp(p, "forward_add", 11)) {
|
||||
do_forward_add(ssl, worker, skipwhite(p+11));
|
||||
} else if(cmdcmp(p, "forward_remove", 14)) {
|
||||
do_forward_remove(ssl, worker, skipwhite(p+14));
|
||||
} else if(cmdcmp(p, "forward", 7)) {
|
||||
do_forward(ssl, worker, skipwhite(p+7));
|
||||
} else if(cmdcmp(p, "stub_add", 8)) {
|
||||
do_stub_add(ssl, worker, skipwhite(p+8));
|
||||
} else if(cmdcmp(p, "stub_remove", 11)) {
|
||||
do_stub_remove(ssl, worker, skipwhite(p+11));
|
||||
} else if(cmdcmp(p, "view_local_zone_remove", 22)) {
|
||||
do_view_zone_remove(ssl, worker, skipwhite(p+22));
|
||||
} else if(cmdcmp(p, "view_local_zone", 15)) {
|
||||
|
|
|
@ -366,9 +366,8 @@ readpid (const char* file)
|
|||
/** write pid to file.
|
||||
* @param pidfile: file name of pid file.
|
||||
* @param pid: pid to write to file.
|
||||
* @return false on failure
|
||||
*/
|
||||
static int
|
||||
static void
|
||||
writepid (const char* pidfile, pid_t pid)
|
||||
{
|
||||
int fd;
|
||||
|
@ -383,7 +382,7 @@ writepid (const char* pidfile, pid_t pid)
|
|||
, 0644)) == -1) {
|
||||
log_err("cannot open pidfile %s: %s",
|
||||
pidfile, strerror(errno));
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
while(count < strlen(pidbuf)) {
|
||||
ssize_t r = write(fd, pidbuf+count, strlen(pidbuf)-count);
|
||||
|
@ -393,17 +392,16 @@ writepid (const char* pidfile, pid_t pid)
|
|||
log_err("cannot write to pidfile %s: %s",
|
||||
pidfile, strerror(errno));
|
||||
close(fd);
|
||||
return 0;
|
||||
return;
|
||||
} else if(r == 0) {
|
||||
log_err("cannot write any bytes to pidfile %s: "
|
||||
"write returns 0 bytes written", pidfile);
|
||||
close(fd);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
count += r;
|
||||
}
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -545,7 +543,15 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
|||
cfg, 1);
|
||||
if(!daemon->pidfile)
|
||||
fatal_exit("pidfile alloc: out of memory");
|
||||
checkoldpid(daemon->pidfile, pidinchroot);
|
||||
/* Check old pid if there is no username configured.
|
||||
* With a username, the assumption is that the privilege
|
||||
* drop makes a pidfile not removed when the server stopped
|
||||
* last time. The server does not chown the pidfile for it,
|
||||
* because that creates privilege escape problems, with the
|
||||
* pidfile writable by unprivileged users, but used by
|
||||
* privileged users. */
|
||||
if(cfg->username && cfg->username[0])
|
||||
checkoldpid(daemon->pidfile, pidinchroot);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -557,18 +563,7 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
|||
/* write new pidfile (while still root, so can be outside chroot) */
|
||||
#ifdef HAVE_KILL
|
||||
if(cfg->pidfile && cfg->pidfile[0] && need_pidfile) {
|
||||
if(writepid(daemon->pidfile, getpid())) {
|
||||
if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1 &&
|
||||
pidinchroot) {
|
||||
# ifdef HAVE_CHOWN
|
||||
if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) {
|
||||
verbose(VERB_QUERY, "cannot chown %u.%u %s: %s",
|
||||
(unsigned)cfg_uid, (unsigned)cfg_gid,
|
||||
daemon->pidfile, strerror(errno));
|
||||
}
|
||||
# endif /* HAVE_CHOWN */
|
||||
}
|
||||
}
|
||||
writepid(daemon->pidfile, getpid());
|
||||
}
|
||||
#else
|
||||
(void)daemon;
|
||||
|
@ -746,7 +741,11 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, int need_pi
|
|||
if(daemon->pidfile) {
|
||||
int fd;
|
||||
/* truncate pidfile */
|
||||
fd = open(daemon->pidfile, O_WRONLY | O_TRUNC, 0644);
|
||||
fd = open(daemon->pidfile, O_WRONLY | O_TRUNC
|
||||
#ifdef O_NOFOLLOW
|
||||
| O_NOFOLLOW
|
||||
#endif
|
||||
, 0644);
|
||||
if(fd != -1)
|
||||
close(fd);
|
||||
/* delete pidfile */
|
||||
|
|
|
@ -659,7 +659,12 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||
if(rep->ttl < timenow) {
|
||||
/* Check if we need to serve expired now */
|
||||
if(worker->env.cfg->serve_expired &&
|
||||
!worker->env.cfg->serve_expired_client_timeout) {
|
||||
!worker->env.cfg->serve_expired_client_timeout
|
||||
#ifdef USE_CACHEDB
|
||||
&& !(worker->env.cachedb_enabled &&
|
||||
worker->env.cfg->cachedb_check_when_serve_expired)
|
||||
#endif
|
||||
) {
|
||||
if(worker->env.cfg->serve_expired_ttl &&
|
||||
rep->serve_expired_ttl < timenow)
|
||||
return 0;
|
||||
|
@ -1454,8 +1459,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||
*/
|
||||
if(worker->dtenv.log_client_query_messages) {
|
||||
log_addr(VERB_ALGO, "request from client", &repinfo->client_addr, repinfo->client_addrlen);
|
||||
log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
|
||||
dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->ssl, c->buffer,
|
||||
log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen);
|
||||
dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer,
|
||||
((worker->env.cfg->sock_queue_timeout && timeval_isset(&c->recv_tv))?&c->recv_tv:NULL));
|
||||
}
|
||||
#endif
|
||||
|
@ -1943,10 +1948,10 @@ send_reply_rc:
|
|||
/*
|
||||
* sending src (client)/dst (local service) addresses over DNSTAP from send_reply code label (when we serviced local zone for ex.)
|
||||
*/
|
||||
if(worker->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);
|
||||
if(worker->dtenv.log_client_response_messages && rc !=0) {
|
||||
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);
|
||||
dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->ssl, c->buffer);
|
||||
dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer);
|
||||
}
|
||||
#endif
|
||||
if(worker->env.cfg->log_replies)
|
||||
|
@ -1961,13 +1966,13 @@ send_reply_rc:
|
|||
log_reply_info(NO_VERBOSE, &qinfo,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
tv, 1, c->buffer,
|
||||
(worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr->ai_addr:NULL),
|
||||
(worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL),
|
||||
c->type);
|
||||
} else {
|
||||
log_reply_info(NO_VERBOSE, &qinfo,
|
||||
&repinfo->client_addr, repinfo->client_addrlen,
|
||||
tv, 1, c->buffer,
|
||||
(worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr->ai_addr:NULL),
|
||||
(worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL),
|
||||
c->type);
|
||||
}
|
||||
}
|
||||
|
@ -2261,18 +2266,6 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
|||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
if(!(worker->env.fwds = forwards_create()) ||
|
||||
!forwards_apply_cfg(worker->env.fwds, cfg)) {
|
||||
log_err("Could not set forward zones");
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
if(!(worker->env.hints = hints_create()) ||
|
||||
!hints_apply_cfg(worker->env.hints, cfg)) {
|
||||
log_err("Could not set root or stub hints");
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
/* one probe timer per process -- if we have 5011 anchors */
|
||||
if(autr_get_num_anchors(worker->env.anchors) > 0
|
||||
#ifndef THREADS_DISABLED
|
||||
|
@ -2345,8 +2338,6 @@ worker_delete(struct worker* worker)
|
|||
outside_network_quit_prepare(worker->back);
|
||||
mesh_delete(worker->env.mesh);
|
||||
sldns_buffer_free(worker->env.scratch_buffer);
|
||||
forwards_delete(worker->env.fwds);
|
||||
hints_delete(worker->env.hints);
|
||||
listen_delete(worker->front);
|
||||
outside_network_delete(worker->back);
|
||||
comm_signal_delete(worker->comsig);
|
||||
|
|
|
@ -1,15 +1,194 @@
|
|||
1 May 2024: Wouter
|
||||
- Fix for the DNSBomb vulnerability CVE-2024-33655. Thanks to Xiang Li
|
||||
from the Network and Information Security Lab of Tsinghua University
|
||||
for reporting it.
|
||||
- Set version number to 1.20.0 for release.
|
||||
|
||||
29 April 2024: Yorgos
|
||||
- Cleanup unnecessary strdup calls for EDE strings.
|
||||
|
||||
29 April 2024: Wouter
|
||||
- Fix doxygen comment for errinf_to_str_bogus.
|
||||
|
||||
26 April 2024: Wouter
|
||||
- Fix cachedb with serve-expired-client-timeout disabled. The edns
|
||||
subnet module deletes global cache and cachedb cache when it
|
||||
stores a result, and serve-expired is enabled, so that the global
|
||||
reply, that is older than the ecs reply, does not return after
|
||||
the ecs reply expires.
|
||||
- Add unit tests for cachedb and subnet cache expired data.
|
||||
- Man page entry for unbound-checkconf -q.
|
||||
|
||||
26 April 2024: Yorgos
|
||||
- Fix #876: [FR] can unbound-checkconf be silenced when configuration
|
||||
is valid?
|
||||
|
||||
25 April 2024: Wouter
|
||||
- Fix configure flto check error, by finding grep for it.
|
||||
- Merge #1041: Stub and Forward unshare. This has one structure
|
||||
for them and fixes #1038: fatal error: Could not initialize
|
||||
thread / error: reading root hints.
|
||||
- Fix to disable fragmentation on systems with IP_DONTFRAG,
|
||||
with a nonzero value for the socket option argument.
|
||||
- Fix doc unit test for out of directory build.
|
||||
|
||||
24 April 2024: Wouter
|
||||
- Fix ci workflow for macos for moved install locations.
|
||||
|
||||
23 April 2024: Yorgos
|
||||
- Merge #1053: Remove child delegations from cache when grandchild
|
||||
delegations are returned from parent.
|
||||
|
||||
22 April 2024: Wouter
|
||||
- Add checklock feature verbose_locking to trace locks and unlocks.
|
||||
- Fix edns subnet to sort rrset references when storing messages
|
||||
in the cache. This fixes a race condition in the rrset locks.
|
||||
|
||||
15 April 2024: Wouter
|
||||
- Fix #1048: Update ax_pkg_swig.m4 and ax_pthread.m4.
|
||||
- Fix configure, autoconf for #1048.
|
||||
|
||||
15 April 2024: Yorgos
|
||||
- Merge #1049 from Petr Menšík: Py_NoSiteFlag is not needed since
|
||||
Python 3.8
|
||||
|
||||
12 April 2024: Wouter
|
||||
- Fix cachedb for serve-expired with serve-expired-client-timeout.
|
||||
- Fixup unit test for cachedb server expired client timeout with
|
||||
a check if response if from upstream or from cachedb.
|
||||
- Fixup cachedb to not refetch when serve-expired-client-timeout is
|
||||
used.
|
||||
|
||||
10 April 2024: Wouter
|
||||
- Implement cachedb-check-when-serve-expired: yes option, default
|
||||
is enabled. When serve expired is enabled with cachedb, it first
|
||||
checks cachedb before serving the expired response.
|
||||
- Fixup compile without cachedb.
|
||||
- Add test for cachedb serve expired.
|
||||
- Extended test for cachedb serve expired.
|
||||
- Fix makefile dependencies for fake_event.c.
|
||||
- Fix cachedb for serve-expired with serve-expired-reply-ttl.
|
||||
- Fix to not reply serve expired unless enabled for cachedb.
|
||||
|
||||
9 April 2024: Yorgos
|
||||
- Merge #1043 from xiaoxiaoafeifei: Add loongarch support; updates
|
||||
config.guess(2024-01-01) and config.sub(2024-01-01), verified
|
||||
with upstream.
|
||||
|
||||
8 April 2024: Yorgos
|
||||
- Fix #595: unbound-anchor cannot deal with full disk; it will now
|
||||
first write out to a temp file before replacing the original one,
|
||||
like Unbound already does for auto-trust-anchor-file.
|
||||
|
||||
5 April 2024: Wouter
|
||||
- Fix comment syntax for view function views_find_view.
|
||||
|
||||
5 April 2024: Yorgos
|
||||
- Merge #1027: Introduce 'cache-min-negative-ttl' option.
|
||||
|
||||
3 April 2024: Wouter
|
||||
- Fix #1040: fix heap-buffer-overflow issue in function cfg_mark_ports
|
||||
of file util/config_file.c.
|
||||
- For #1040: adjust error text and disallow negative ports in other
|
||||
parts of cfg_mark_ports.
|
||||
|
||||
3 April 2024: Yorgos
|
||||
- Fix #1035: Potential Bug while parsing port from the "stub-host"
|
||||
string; also affected forward-zones and remote-control host
|
||||
directives.
|
||||
- Fix #369: dnstap showing extra responses; for client responses
|
||||
right from the cache when replying with expired data or
|
||||
prefetching.
|
||||
|
||||
28 March 2024: Wouter
|
||||
- Fix #1034: DoT forward-zone via unbound-control.
|
||||
- Fix for crypto related failures to have a better error string.
|
||||
|
||||
27 March 2024: Wouter
|
||||
- Fix name of unit test for subnet cache response.
|
||||
- Fix #1032: The size of subnet_msg_cache calculation mistake cause
|
||||
memory usage increased beyond expectations.
|
||||
- Fix for #1032, add safeguard to make table space positive.
|
||||
- Fix comment in lruhash space function.
|
||||
- Fix to add unit test for lruhash space that exercises the routines.
|
||||
- Fix that when the server truncates the pidfile, it does not follow
|
||||
symbolic links.
|
||||
- Fix that the server does not chown the pidfile.
|
||||
|
||||
25 March 2024: Yorgos
|
||||
- Merge #831 from Pierre4012: Improve Windows NSIS installer
|
||||
script (setup.nsi).
|
||||
- For #831: Format text, use exclamation icon and explicit label
|
||||
names.
|
||||
|
||||
19 March 2024: Wouter
|
||||
- Fix rpz so that rpz CNAME can apply after rpz CNAME. And fix that
|
||||
clientip and nsip can give a CNAME.
|
||||
- Fix localdata and rpz localdata to match CNAME only if no direct
|
||||
type match is available.
|
||||
|
||||
18 March 2024: Wouter
|
||||
- Fix that rpz CNAME content is limited to the max number of cnames.
|
||||
- Fix rpz, it follows iterator CNAMEs for nsip and nsdname and sets
|
||||
the reply query_info values, that is better for debug logging.
|
||||
- Fix rpz that copies the cname override completely to the temp
|
||||
region, so there are no references to the rpz region.
|
||||
- Add rpz unit test for nsip action override.
|
||||
- Fix rpz for qtype CNAME after nameserver trigger.
|
||||
|
||||
15 March 2024: Yorgos
|
||||
- Merge #1030: Persist the openssl and expat directories for repeated
|
||||
Windows builds.
|
||||
|
||||
15 March 2024: Wouter
|
||||
- Fix that addrinfo is not kept around but copied and freed, so that
|
||||
log-destaddr uses a copy of the information, much like NSD does.
|
||||
|
||||
13 March 2024: Wouter
|
||||
- Fix #1029: rpz trigger clientip and action rpz-passthru not working
|
||||
as expected.
|
||||
- Fix rpz that the rpz override is taken in case of clientip triggers.
|
||||
Fix that the clientip passthru action is logged. Fix that the
|
||||
clientip localdata action is logged. Fix rpz override action cname
|
||||
for the clientip trigger.
|
||||
- Fix to unify codepath for local alias for rpz cname action override.
|
||||
- Fix rpz for cname override action after nsdname and nsip triggers.
|
||||
|
||||
12 March 2024: Yorgos
|
||||
- Merge #1028: Clearer documentation for tcp-idle-timeout and
|
||||
edns-tcp-keepalive-timeout.
|
||||
|
||||
11 March 2024: Wouter
|
||||
- Fix #1021 Inconsistent Behavior with Changing rpz-cname-override
|
||||
and doing a unbound-control reload.
|
||||
|
||||
8 March 2024: Wouter
|
||||
- Fix unbound-control-setup.cmd to use 3072 bits so that certificates
|
||||
are long enough for newer OpenSSL versions.
|
||||
- Fix TTL of synthesized CNAME when a DNAME is used from cache.
|
||||
are long enough for newer OpenSSL versions. This fix is included
|
||||
in 1.19.3rc2.
|
||||
- Fix TTL of synthesized CNAME when a DNAME is used from cache. This
|
||||
fix is included in 1.19.3rc2.
|
||||
- Remove unused portion from iter_dname_ttl unit test.
|
||||
- Fix validator classification of qtype DNAME for positive and
|
||||
redirection answers, and fix validator signature routine for dealing
|
||||
with the synthesized CNAME for a DNAME without previously
|
||||
encountering it and also for when the qtype is DNAME.
|
||||
- Fix qname minimisation for reply with a DNAME for qtype CNAME that
|
||||
answers it.
|
||||
- Fix doc test so it ignores but outputs unsupported doxygen options.
|
||||
- Fix unbound-control-setup.cmd to have CA v3 basicConstraints,
|
||||
like unbound-control-setup.sh has.
|
||||
like unbound-control-setup.sh has. This fix is included in 1.19.3rc2.
|
||||
|
||||
8 March 2024: Yorgos
|
||||
- Update doc/unbound.doxygen with 'doxygen -u'. Fixes option
|
||||
deprecation warnings and updates with newer defaults.
|
||||
|
||||
7 March 2024: Wouter
|
||||
- Version set to 1.19.3 for release. After 1.19.2 point release with
|
||||
security fix for CVE-2024-1931, Denial of service when trimming
|
||||
EDE text on positive replies. The code repo includes the fix and
|
||||
is for version 1.19.3.
|
||||
is for version 1.19.3. The code repo continues for version 1.19.4,
|
||||
but 1.19.3 includes the fixes in 1.19.3rc2 as well.
|
||||
|
||||
5 March 2024: Wouter
|
||||
- Fix for #1022: Fix ede prohibited in access control refused answers.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
README for Unbound 1.19.3
|
||||
README for Unbound 1.20.0
|
||||
Copyright 2007 NLnet Labs
|
||||
http://unbound.net
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#
|
||||
# Example configuration file.
|
||||
#
|
||||
# See unbound.conf(5) man page, version 1.19.3.
|
||||
# See unbound.conf(5) man page, version 1.20.0.
|
||||
#
|
||||
# this is a comment.
|
||||
|
||||
|
@ -191,6 +191,21 @@ server:
|
|||
# are behind a slow satellite link, to eg. 1128.
|
||||
# unknown-server-time-limit: 376
|
||||
|
||||
# msec before recursion replies are dropped. The work item continues.
|
||||
# discard-timeout: 1900
|
||||
|
||||
# Max number of replies waiting for recursion per IP address.
|
||||
# wait-limit: 1000
|
||||
|
||||
# Max replies waiting for recursion for IP address with cookie.
|
||||
# wait-limit-cookie: 10000
|
||||
|
||||
# Apart from the default, the wait limit can be set for a netblock.
|
||||
# wait-limit-netblock: 192.0.2.0/24 50000
|
||||
|
||||
# Apart from the default, the wait limit with cookie can be adjusted.
|
||||
# wait-limit-cookie-netblock: 192.0.2.0/24 50000
|
||||
|
||||
# the amount of memory to use for the RRset cache.
|
||||
# plain value in bytes or you can append k, m or G. default is "4Mb".
|
||||
# rrset-cache-size: 4m
|
||||
|
@ -211,6 +226,11 @@ server:
|
|||
# the time to live (TTL) value cap for negative responses in the cache
|
||||
# cache-max-negative-ttl: 3600
|
||||
|
||||
# the time to live (TTL) value lower bound, in seconds. Default 0.
|
||||
# For negative responses in the cache. If disabled, default,
|
||||
# cache-min-tll applies if configured.
|
||||
# cache-min-negative-ttl: 0
|
||||
|
||||
# the time to live (TTL) value for cached roundtrip times, lameness and
|
||||
# EDNS version information for hosts. In seconds.
|
||||
# infra-host-ttl: 900
|
||||
|
@ -283,7 +303,8 @@ server:
|
|||
# Enable EDNS TCP keepalive option.
|
||||
# edns-tcp-keepalive: no
|
||||
|
||||
# Timeout for EDNS TCP keepalive, in msec.
|
||||
# Timeout for EDNS TCP keepalive, in msec. Overrides tcp-idle-timeout
|
||||
# if edns-tcp-keepalive is set.
|
||||
# edns-tcp-keepalive-timeout: 120000
|
||||
|
||||
# UDP queries that have waited in the socket buffer for a long time
|
||||
|
@ -1247,6 +1268,9 @@ remote-control:
|
|||
# secret-seed: "default"
|
||||
# # if the backend should be read from, but not written to.
|
||||
# cachedb-no-store: no
|
||||
# # if the cachedb should be checked before a serve-expired response is
|
||||
# # given, when serve-expired is enabled.
|
||||
# cachedb-check-when-serve-expired: yes
|
||||
#
|
||||
# # For "redis" backend:
|
||||
# # (to enable, use --with-libhiredis to configure before compiling)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH "libunbound" "3" "Mar 14, 2024" "NLnet Labs" "unbound 1.19.3"
|
||||
.TH "libunbound" "3" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
|
||||
.\"
|
||||
.\" libunbound.3 -- unbound library functions manual
|
||||
.\"
|
||||
|
@ -44,7 +44,7 @@
|
|||
.B ub_ctx_zone_remove,
|
||||
.B ub_ctx_data_add,
|
||||
.B ub_ctx_data_remove
|
||||
\- Unbound DNS validating resolver 1.19.3 functions.
|
||||
\- Unbound DNS validating resolver 1.20.0 functions.
|
||||
.SH "SYNOPSIS"
|
||||
.B #include <unbound.h>
|
||||
.LP
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH "unbound-anchor" "8" "Mar 14, 2024" "NLnet Labs" "unbound 1.19.3"
|
||||
.TH "unbound-anchor" "8" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
|
||||
.\"
|
||||
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
|
||||
.\"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH "unbound-checkconf" "8" "Mar 14, 2024" "NLnet Labs" "unbound 1.19.3"
|
||||
.TH "unbound-checkconf" "8" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
|
||||
.\"
|
||||
.\" unbound-checkconf.8 -- unbound configuration checker manual
|
||||
.\"
|
||||
|
@ -14,6 +14,7 @@ unbound\-checkconf
|
|||
.B unbound\-checkconf
|
||||
.RB [ \-h ]
|
||||
.RB [ \-f ]
|
||||
.RB [ \-q ]
|
||||
.RB [ \-o
|
||||
.IR option ]
|
||||
.RI [ cfgfile ]
|
||||
|
@ -37,6 +38,9 @@ Print full pathname, with chroot applied to it. Use with the \-o option.
|
|||
If given, after checking the config file the value of this option is
|
||||
printed to stdout. For "" (disabled) options an empty line is printed.
|
||||
.TP
|
||||
.B \-q
|
||||
Make the operation quiet, suppress output on success.
|
||||
.TP
|
||||
.I cfgfile
|
||||
The config file to read with settings for Unbound. It is checked.
|
||||
If omitted, the config file at the default location is checked.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH "unbound-control" "8" "Mar 14, 2024" "NLnet Labs" "unbound 1.19.3"
|
||||
.TH "unbound-control" "8" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
|
||||
.\"
|
||||
.\" unbound-control.8 -- unbound remote control manual
|
||||
.\"
|
||||
|
@ -239,22 +239,24 @@ still be bogus, use \fBflush_zone\fR to remove it), does not affect the config f
|
|||
.B insecure_remove \fIzone
|
||||
Removes domain\-insecure for the given zone.
|
||||
.TP
|
||||
.B forward_add \fR[\fI+i\fR] \fIzone addr ...
|
||||
.B forward_add \fR[\fI+it\fR] \fIzone addr ...
|
||||
Add a new forward zone to running Unbound. With +i option also adds a
|
||||
\fIdomain\-insecure\fR for the zone (so it can resolve insecurely if you have
|
||||
a DNSSEC root trust anchor configured for other names).
|
||||
The addr can be IP4, IP6 or nameserver names, like \fIforward-zone\fR config
|
||||
in unbound.conf.
|
||||
The +t option sets it to use tls upstream, like \fIforward\-tls\-upstream\fR: yes.
|
||||
.TP
|
||||
.B forward_remove \fR[\fI+i\fR] \fIzone
|
||||
Remove a forward zone from running Unbound. The +i also removes a
|
||||
\fIdomain\-insecure\fR for the zone.
|
||||
.TP
|
||||
.B stub_add \fR[\fI+ip\fR] \fIzone addr ...
|
||||
.B stub_add \fR[\fI+ipt\fR] \fIzone addr ...
|
||||
Add a new stub zone to running Unbound. With +i option also adds a
|
||||
\fIdomain\-insecure\fR for the zone. With +p the stub zone is set to prime,
|
||||
without it it is set to notprime. The addr can be IP4, IP6 or nameserver
|
||||
names, like the \fIstub-zone\fR config in unbound.conf.
|
||||
The +t option sets it to use tls upstream, like \fIstub\-tls\-upstream\fR: yes.
|
||||
.TP
|
||||
.B stub_remove \fR[\fI+i\fR] \fIzone
|
||||
Remove a stub zone from running Unbound. The +i also removes a
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH "unbound\-host" "1" "Mar 14, 2024" "NLnet Labs" "unbound 1.19.3"
|
||||
.TH "unbound\-host" "1" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
|
||||
.\"
|
||||
.\" unbound-host.1 -- unbound DNS lookup utility
|
||||
.\"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH "unbound" "8" "Mar 14, 2024" "NLnet Labs" "unbound 1.19.3"
|
||||
.TH "unbound" "8" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
|
||||
.\"
|
||||
.\" unbound.8 -- unbound manual
|
||||
.\"
|
||||
|
@ -9,7 +9,7 @@
|
|||
.\"
|
||||
.SH "NAME"
|
||||
.B unbound
|
||||
\- Unbound DNS validating resolver 1.19.3.
|
||||
\- Unbound DNS validating resolver 1.20.0.
|
||||
.SH "SYNOPSIS"
|
||||
.B unbound
|
||||
.RB [ \-h ]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH "unbound.conf" "5" "Mar 14, 2024" "NLnet Labs" "unbound 1.19.3"
|
||||
.TH "unbound.conf" "5" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
|
||||
.\"
|
||||
.\" unbound.conf.5 -- unbound.conf manual
|
||||
.\"
|
||||
|
@ -266,6 +266,36 @@ Increase this if you are behind a slow satellite link, to eg. 1128.
|
|||
That would then avoid re\-querying every initial query because it times out.
|
||||
Default is 376 msec.
|
||||
.TP
|
||||
.B discard\-timeout: \fI<msec>
|
||||
The wait time in msec where recursion requests are dropped. This is
|
||||
to stop a large number of replies from accumulating. They receive
|
||||
no reply, the work item continues to recurse. It is nice to be a bit
|
||||
larger than serve\-expired\-client\-timeout if that is enabled.
|
||||
A value of 1900 msec is suggested. The value 0 disables it.
|
||||
Default 1900 msec.
|
||||
.TP
|
||||
.B wait\-limit: \fI<number>
|
||||
The number of replies that can wait for recursion, for an IP address.
|
||||
This makes a ratelimit per IP address of waiting replies for recursion.
|
||||
It stops very large amounts of queries waiting to be returned to one
|
||||
destination. The value 0 disables wait limits. Default is 1000.
|
||||
.TP
|
||||
.B wait\-limit\-cookie: \fI<number>
|
||||
The number of replies that can wait for recursion, for an IP address
|
||||
that sent the query with a valid DNS cookie. Since the cookie validates
|
||||
the client address, the limit can be higher. Default is 10000.
|
||||
.TP
|
||||
.B wait\-limit\-netblock: \fI<netblock> <number>
|
||||
The wait limit for the netblock. If not given the wait\-limit value is
|
||||
used. The most specific netblock is used to determine the limit. Useful for
|
||||
overriding the default for a specific, group or individual, server.
|
||||
The value -1 disables wait limits for the netblock.
|
||||
.TP
|
||||
.B wait\-limit\-cookie\-netblock: \fI<netblock> <number>
|
||||
The wait limit for the netblock, when the query has a DNS cookie.
|
||||
If not given, the wait\-limit\-cookie value is used.
|
||||
The value -1 disables wait limits for the netblock.
|
||||
.TP
|
||||
.B so\-rcvbuf: \fI<number>
|
||||
If not 0, then set the SO_RCVBUF socket option to get more buffer
|
||||
space on UDP port 53 incoming queries. So that short spikes on busy
|
||||
|
@ -352,6 +382,15 @@ Time to live maximum for negative responses, these have a SOA in the
|
|||
authority section that is limited in time. Default is 3600.
|
||||
This applies to nxdomain and nodata answers.
|
||||
.TP
|
||||
.B cache\-min\-negative\-ttl: \fI<seconds>
|
||||
Time to live minimum for negative responses, these have a SOA in the
|
||||
authority section that is limited in time.
|
||||
Default is 0 (disabled).
|
||||
If this is disabled and \fBcache-min-ttl\fR is configured, it will take effect
|
||||
instead.
|
||||
In that case you can set this to 1 to honor the upstream TTL.
|
||||
This applies to nxdomain and nodata answers.
|
||||
.TP
|
||||
.B infra\-host\-ttl: \fI<seconds>
|
||||
Time to live for entries in the host cache. The host cache contains
|
||||
roundtrip timing, lameness and EDNS support information. Default is 900.
|
||||
|
@ -436,6 +475,8 @@ configured value if the number of free buffers falls below 35% of the
|
|||
total number configured, and finally to 0 if the number of free buffers
|
||||
falls below 20% of the total number configured. A minimum timeout of
|
||||
200 milliseconds is observed regardless of the option value used.
|
||||
It will be overriden by \fBedns\-tcp\-keepalive\-timeout\fR if
|
||||
\fBedns\-tcp\-keepalive\fR is enabled.
|
||||
.TP
|
||||
.B tcp-reuse-timeout: \fI<msec>\fR
|
||||
The period Unbound will keep TCP persistent connections open to
|
||||
|
@ -454,20 +495,11 @@ This option defaults to 3000 milliseconds.
|
|||
Enable or disable EDNS TCP Keepalive. Default is no.
|
||||
.TP
|
||||
.B edns-tcp-keepalive-timeout: \fI<msec>\fR
|
||||
The period Unbound will wait for a query on a TCP connection when
|
||||
EDNS TCP Keepalive is active. If this timeout expires Unbound closes
|
||||
the connection. If the client supports the EDNS TCP Keepalive option,
|
||||
Overrides \fBtcp\-idle\-timeout\fR when \fBedns\-tcp\-keepalive\fR is enabled.
|
||||
If the client supports the EDNS TCP Keepalive option,
|
||||
Unbound sends the timeout value to the client to encourage it to
|
||||
close the connection before the server times out.
|
||||
This option defaults to 120000 milliseconds.
|
||||
When the number of free incoming TCP buffers falls below 50% of
|
||||
the total number configured, the advertised timeout is progressively
|
||||
reduced to 1% of the configured value, then to 0.2% of the configured
|
||||
value if the number of free buffers falls below 35% of the total number
|
||||
configured, and finally to 0 if the number of free buffers falls below
|
||||
20% of the total number configured.
|
||||
A minimum actual timeout of 200 milliseconds is observed regardless of the
|
||||
advertised timeout.
|
||||
.TP
|
||||
.B sock\-queue\-timeout: \fI<sec>\fR
|
||||
UDP queries that have waited in the socket buffer for a long time can be
|
||||
|
@ -2593,11 +2625,7 @@ If Unbound cannot even find an answer in the backend, it resolves the
|
|||
query as usual, and stores the answer in the backend.
|
||||
.P
|
||||
This module interacts with the \fBserve\-expired\-*\fR options and will reply
|
||||
with expired data if Unbound is configured for that. Currently the use
|
||||
of \fBserve\-expired\-client\-timeout:\fR and
|
||||
\fBserve\-expired\-reply\-ttl:\fR is not consistent for data originating from
|
||||
the external cache as these will result in a reply with 0 TTL without trying to
|
||||
update the data first, ignoring the configured values.
|
||||
with expired data if Unbound is configured for that.
|
||||
.P
|
||||
If Unbound was built with
|
||||
\fB\-\-with\-libhiredis\fR
|
||||
|
@ -2653,6 +2681,16 @@ This option defaults to "default".
|
|||
If the backend should be read from, but not written to. This makes this
|
||||
instance not store dns messages in the backend. But if data is available it
|
||||
is retrieved. The default is no.
|
||||
.TP
|
||||
.B cachedb-check-when-serve-expired: \fI<yes or no>\fR
|
||||
If enabled, the cachedb is checked before an expired response is returned.
|
||||
When \fBserve\-expired\fR is enabled, without \fBserve\-expired\-client\-timeout\fR, it then
|
||||
does not immediately respond with an expired response from cache, but instead
|
||||
first checks the cachedb for valid contents, and if so returns it. If the
|
||||
cachedb also has no valid contents, the serve expired response is sent.
|
||||
If also \fBserve\-expired\-client\-timeout\fR is enabled, the expired response
|
||||
is delayed until the timeout expires. Unless the lookup succeeds within the
|
||||
timeout. The default is yes.
|
||||
.P
|
||||
The following
|
||||
.B cachedb
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -57,6 +57,9 @@
|
|||
#include "sldns/sbuffer.h"
|
||||
#include "sldns/wire2str.h"
|
||||
#include "iterator/iter_utils.h"
|
||||
#ifdef USE_CACHEDB
|
||||
#include "cachedb/cachedb.h"
|
||||
#endif
|
||||
|
||||
/** externally called */
|
||||
void
|
||||
|
@ -152,7 +155,7 @@ int ecs_whitelist_check(struct query_info* qinfo,
|
|||
|
||||
/* Cache by default, might be disabled after parsing EDNS option
|
||||
* received from nameserver. */
|
||||
if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL)) {
|
||||
if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) {
|
||||
qstate->no_cache_store = 0;
|
||||
}
|
||||
|
||||
|
@ -310,9 +313,18 @@ delfunc(void *envptr, void *elemptr) {
|
|||
static size_t
|
||||
sizefunc(void *elemptr) {
|
||||
struct reply_info *elem = (struct reply_info *)elemptr;
|
||||
return sizeof (struct reply_info) - sizeof (struct rrset_ref)
|
||||
size_t s = sizeof (struct reply_info) - sizeof (struct rrset_ref)
|
||||
+ elem->rrset_count * sizeof (struct rrset_ref)
|
||||
+ elem->rrset_count * sizeof (struct ub_packed_rrset_key *);
|
||||
size_t i;
|
||||
for (i = 0; i < elem->rrset_count; i++) {
|
||||
struct ub_packed_rrset_key *key = elem->rrsets[i];
|
||||
struct packed_rrset_data *data = key->entry.data;
|
||||
s += ub_rrset_sizefunc(key, data);
|
||||
}
|
||||
if(elem->reason_bogus_str)
|
||||
s += strlen(elem->reason_bogus_str)+1;
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -352,7 +364,7 @@ update_cache(struct module_qstate *qstate, int id)
|
|||
struct slabhash *subnet_msg_cache = sne->subnet_msg_cache;
|
||||
struct ecs_data *edns = &sq->ecs_client_in;
|
||||
size_t i;
|
||||
int only_match_scope_zero;
|
||||
int only_match_scope_zero, diff_size;
|
||||
|
||||
/* We already calculated hash upon lookup (lookup_and_reply) if we were
|
||||
* allowed to look in the ECS cache */
|
||||
|
@ -412,19 +424,25 @@ update_cache(struct module_qstate *qstate, int id)
|
|||
rep->ref[i].id = rep->rrsets[i]->id;
|
||||
}
|
||||
reply_info_set_ttls(rep, *qstate->env->now);
|
||||
reply_info_sortref(rep);
|
||||
rep->flags |= (BIT_RA | BIT_QR); /* fix flags to be sensible for */
|
||||
rep->flags &= ~(BIT_AA | BIT_CD);/* a reply based on the cache */
|
||||
if(edns->subnet_source_mask == 0 && edns->subnet_scope_mask == 0)
|
||||
only_match_scope_zero = 1;
|
||||
else only_match_scope_zero = 0;
|
||||
diff_size = (int)tree->size_bytes;
|
||||
addrtree_insert(tree, (addrkey_t*)edns->subnet_addr,
|
||||
edns->subnet_source_mask, sq->max_scope, rep,
|
||||
rep->ttl, *qstate->env->now, only_match_scope_zero);
|
||||
diff_size = (int)tree->size_bytes - diff_size;
|
||||
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
if (need_to_insert) {
|
||||
slabhash_insert(subnet_msg_cache, h, lru_entry, lru_entry->data,
|
||||
NULL);
|
||||
} else {
|
||||
slabhash_update_space_used(subnet_msg_cache, h, NULL,
|
||||
diff_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,6 +606,20 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
|||
sne->num_msg_nocache++;
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
|
||||
/* If there is an expired answer in the global cache, remove that,
|
||||
* because expired answers would otherwise resurface once the ecs data
|
||||
* expires, giving once in a while global data responses for ecs
|
||||
* domains, with serve expired enabled. */
|
||||
if(qstate->env->cfg->serve_expired) {
|
||||
msg_cache_remove(qstate->env, qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len, qstate->qinfo.qtype,
|
||||
qstate->qinfo.qclass, 0);
|
||||
#ifdef USE_CACHEDB
|
||||
if(qstate->env->cachedb_enabled)
|
||||
cachedb_msg_remove(qstate);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sq->subnet_downstream) {
|
||||
/* Client wants to see the answer, echo option back
|
||||
* and adjust the scope. */
|
||||
|
|
|
@ -71,6 +71,7 @@ forwards_create(void)
|
|||
sizeof(struct iter_forwards));
|
||||
if(!fwd)
|
||||
return NULL;
|
||||
lock_rw_init(&fwd->lock);
|
||||
return fwd;
|
||||
}
|
||||
|
||||
|
@ -100,6 +101,7 @@ forwards_delete(struct iter_forwards* fwd)
|
|||
{
|
||||
if(!fwd)
|
||||
return;
|
||||
lock_rw_destroy(&fwd->lock);
|
||||
fwd_del_tree(fwd);
|
||||
free(fwd);
|
||||
}
|
||||
|
@ -332,45 +334,64 @@ make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg)
|
|||
int
|
||||
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->tree = rbtree_create(fwd_cmp);
|
||||
if(!fwd->tree)
|
||||
return 0;
|
||||
lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree));
|
||||
|
||||
lock_rw_wrlock(&fwd->lock);
|
||||
/* read forward zones */
|
||||
if(!read_forwards(fwd, cfg))
|
||||
if(!read_forwards(fwd, cfg)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
return 0;
|
||||
if(!make_stub_holes(fwd, cfg))
|
||||
}
|
||||
if(!make_stub_holes(fwd, cfg)) {
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
return 0;
|
||||
}
|
||||
fwd_init_parents(fwd);
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
int has_dp;
|
||||
key.node.key = &key;
|
||||
key.dclass = qclass;
|
||||
key.name = qname;
|
||||
key.namelabs = dname_count_size_labels(qname, &key.namelen);
|
||||
res = rbtree_search(fwd->tree, &key);
|
||||
if(res) return ((struct iter_forward_zone*)res)->dp;
|
||||
return NULL;
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(!nolock) { lock_rw_rdlock(&fwd->lock); }
|
||||
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*
|
||||
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 */
|
||||
rbnode_type* res = NULL;
|
||||
struct iter_forward_zone *result;
|
||||
struct iter_forward_zone key;
|
||||
int has_dp;
|
||||
key.node.key = &key;
|
||||
key.dclass = qclass;
|
||||
key.name = qname;
|
||||
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)) {
|
||||
/* exact */
|
||||
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) */
|
||||
int m;
|
||||
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;
|
||||
}
|
||||
/* count number of labels matched */
|
||||
(void)dname_lab_cmp(result->name, result->namelabs, key.name,
|
||||
key.namelabs, &m);
|
||||
|
@ -389,20 +412,22 @@ forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass)
|
|||
result = result->parent;
|
||||
}
|
||||
}
|
||||
if(result)
|
||||
return result->dp;
|
||||
return NULL;
|
||||
has_dp = result && result->dp;
|
||||
if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); }
|
||||
return has_dp?result->dp:NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
return forwards_lookup(fwd, &root, qclass);
|
||||
return forwards_lookup(fwd, &root, qclass, nolock);
|
||||
}
|
||||
|
||||
int
|
||||
forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass)
|
||||
/* Finds next root item in forwards lookup tree.
|
||||
* 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;
|
||||
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 */
|
||||
*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
|
||||
* 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 */
|
||||
*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
|
||||
forwards_get_mem(struct iter_forwards* fwd)
|
||||
{
|
||||
|
@ -458,10 +494,12 @@ forwards_get_mem(struct iter_forwards* fwd)
|
|||
size_t s;
|
||||
if(!fwd)
|
||||
return 0;
|
||||
lock_rw_rdlock(&fwd->lock);
|
||||
s = sizeof(*fwd) + sizeof(*fwd->tree);
|
||||
RBTREE_FOR(p, struct iter_forward_zone*, fwd->tree) {
|
||||
s += sizeof(*p) + p->namelen + delegpt_get_mem(p->dp);
|
||||
}
|
||||
lock_rw_unlock(&fwd->lock);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -477,49 +515,78 @@ fwd_zone_find(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
|||
}
|
||||
|
||||
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;
|
||||
/* 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) {
|
||||
(void)rbtree_delete(fwd->tree, &z->node);
|
||||
fwd_zone_free(z);
|
||||
}
|
||||
if(!forwards_insert(fwd, c, dp))
|
||||
return 0;
|
||||
fwd_init_parents(fwd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
struct iter_forward_zone *z;
|
||||
if(!(z=fwd_zone_find(fwd, c, nm)))
|
||||
return; /* nothing to do */
|
||||
(void)rbtree_delete(fwd->tree, &z->node);
|
||||
fwd_zone_free(z);
|
||||
fwd_init_parents(fwd);
|
||||
}
|
||||
|
||||
int
|
||||
forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
|
||||
{
|
||||
if(!fwd_add_stub_hole(fwd, c, nm)) {
|
||||
if(!forwards_insert(fwd, c, dp)) {
|
||||
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)
|
||||
forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
|
||||
int nolock)
|
||||
{
|
||||
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 */
|
||||
if(z->dp != NULL)
|
||||
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); }
|
||||
}
|
||||
|
||||
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); }
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#ifndef ITERATOR_ITER_FWD_H
|
||||
#define ITERATOR_ITER_FWD_H
|
||||
#include "util/rbtree.h"
|
||||
#include "util/locks.h"
|
||||
struct config_file;
|
||||
struct delegpt;
|
||||
|
||||
|
@ -50,6 +51,11 @@ struct delegpt;
|
|||
* Iterator forward zones structure
|
||||
*/
|
||||
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.
|
||||
* 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
|
||||
* 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 qname: The qname 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.
|
||||
*/
|
||||
struct delegpt* forwards_find(struct iter_forwards* fwd, uint8_t* qname,
|
||||
uint16_t qclass);
|
||||
uint16_t qclass, int nolock);
|
||||
|
||||
/**
|
||||
* Find forward zone information
|
||||
* For this qname/qclass find forward zone information, returns delegation
|
||||
* point with server names and addresses, or NULL if no forwarding is needed.
|
||||
* 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 qname: The qname 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,
|
||||
* otherwise null.
|
||||
*/
|
||||
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
|
||||
* @param fwd: forward storage.
|
||||
* @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.
|
||||
*/
|
||||
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.
|
||||
* 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 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.
|
||||
*/
|
||||
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
|
||||
* Locks and unlocks the structure.
|
||||
* @param fwd: forward storage.
|
||||
* @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
|
||||
* 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 c: class of zone
|
||||
* @param dp: delegation point with name and target nameservers for new
|
||||
* forward zone. malloced.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return false on failure (out of memory);
|
||||
*/
|
||||
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
|
||||
* 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 c: class of zone
|
||||
* @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
|
||||
* a forward-zone because the stub zone should override the forward zone).
|
||||
* 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 c: class of zone
|
||||
* @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);
|
||||
*/
|
||||
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.
|
||||
* 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 c: class of zone
|
||||
* @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,
|
||||
uint8_t* nm);
|
||||
uint8_t* nm, int nolock);
|
||||
|
||||
#endif /* ITERATOR_ITER_FWD_H */
|
||||
|
|
|
@ -57,6 +57,8 @@ hints_create(void)
|
|||
sizeof(struct iter_hints));
|
||||
if(!hints)
|
||||
return NULL;
|
||||
lock_rw_init(&hints->lock);
|
||||
lock_protect(&hints->lock, &hints->tree, sizeof(hints->tree));
|
||||
return hints;
|
||||
}
|
||||
|
||||
|
@ -83,6 +85,7 @@ hints_delete(struct iter_hints* hints)
|
|||
{
|
||||
if(!hints)
|
||||
return;
|
||||
lock_rw_destroy(&hints->lock);
|
||||
hints_del_tree(hints);
|
||||
free(hints);
|
||||
}
|
||||
|
@ -438,47 +441,70 @@ read_root_hints_list(struct iter_hints* hints, struct config_file* cfg)
|
|||
int
|
||||
hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
|
||||
{
|
||||
int nolock = 1;
|
||||
lock_rw_wrlock(&hints->lock);
|
||||
hints_del_tree(hints);
|
||||
name_tree_init(&hints->tree);
|
||||
|
||||
/* read root hints */
|
||||
if(!read_root_hints_list(hints, cfg))
|
||||
if(!read_root_hints_list(hints, cfg)) {
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read stub hints */
|
||||
if(!read_stubs(hints, cfg))
|
||||
if(!read_stubs(hints, cfg)) {
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
cfg->do_ip6);
|
||||
verbose(VERB_ALGO, "no config, using builtin root hints.");
|
||||
if(!dp)
|
||||
if(!dp) {
|
||||
lock_rw_unlock(&hints->lock);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
name_tree_init_parents(&hints->tree);
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
struct iter_hints_stub *stub;
|
||||
stub = (struct iter_hints_stub*)name_tree_find(&hints->tree,
|
||||
&rootlab, 1, 1, qclass);
|
||||
if(!stub)
|
||||
return NULL;
|
||||
return stub->dp;
|
||||
return hints_find(hints, &rootlab, qclass, nolock);
|
||||
}
|
||||
|
||||
struct iter_hints_stub*
|
||||
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;
|
||||
int labs;
|
||||
|
@ -486,14 +512,20 @@ hints_lookup_stub(struct iter_hints* hints, uint8_t* qname,
|
|||
|
||||
/* first lookup the stub */
|
||||
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,
|
||||
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(cache_dp == NULL) {
|
||||
if(r->dp->namelabs != 1)
|
||||
return r; /* no cache dp, use any non-root stub */
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
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,
|
||||
cache_dp->name, cache_dp->namelabs))
|
||||
return r; /* need to prime this stub */
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
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
|
||||
|
@ -524,39 +562,52 @@ hints_get_mem(struct iter_hints* hints)
|
|||
size_t s;
|
||||
struct iter_hints_stub* p;
|
||||
if(!hints) return 0;
|
||||
lock_rw_rdlock(&hints->lock);
|
||||
s = sizeof(*hints);
|
||||
RBTREE_FOR(p, struct iter_hints_stub*, &hints->tree) {
|
||||
s += sizeof(*p) + delegpt_get_mem(p->dp);
|
||||
}
|
||||
lock_rw_unlock(&hints->lock);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp,
|
||||
int noprime)
|
||||
int noprime, int nolock)
|
||||
{
|
||||
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,
|
||||
dp->name, dp->namelen, dp->namelabs, c)) != NULL) {
|
||||
(void)rbtree_delete(&hints->tree, &z->node);
|
||||
hints_stub_free(z);
|
||||
}
|
||||
if(!hints_insert(hints, c, dp, noprime))
|
||||
if(!hints_insert(hints, c, dp, noprime)) {
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return 0;
|
||||
}
|
||||
name_tree_init_parents(&hints->tree);
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
size_t 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,
|
||||
nm, len, labs, c)))
|
||||
nm, len, labs, c))) {
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
return; /* nothing to do */
|
||||
}
|
||||
(void)rbtree_delete(&hints->tree, &z->node);
|
||||
hints_stub_free(z);
|
||||
name_tree_init_parents(&hints->tree);
|
||||
if(!nolock) { lock_rw_unlock(&hints->lock); }
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#ifndef ITERATOR_ITER_HINTS_H
|
||||
#define ITERATOR_ITER_HINTS_H
|
||||
#include "util/storage/dnstree.h"
|
||||
#include "util/locks.h"
|
||||
struct iter_env;
|
||||
struct config_file;
|
||||
struct delegpt;
|
||||
|
@ -51,6 +52,10 @@ struct delegpt;
|
|||
* Iterator hints structure
|
||||
*/
|
||||
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.
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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 qname: the qname that generated the delegation point.
|
||||
* @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_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).
|
||||
* 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 qclass: class for which root hints are sought.
|
||||
* 0 means give the first available root hints class.
|
||||
* x means, give class x or a higher class if any.
|
||||
* returns the found class in this variable.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return true if a root hint class is found.
|
||||
* false if not root hint class is found (qclass may have been changed).
|
||||
*/
|
||||
int hints_next_root(struct iter_hints* hints, uint16_t* qclass);
|
||||
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
|
||||
* for this qname/qclass, determine if this combination indicates that a
|
||||
* 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 qname: The qname that generated the delegation point.
|
||||
* @param qclass: The qclass that generated the 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
|
||||
* be primed, otherwise null.
|
||||
*/
|
||||
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
|
||||
* Locks and unlocks the structure.
|
||||
* @param hints: hint storage.
|
||||
* @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
|
||||
* 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 c: class of zone
|
||||
* @param dp: delegation point with name and target nameservers for new
|
||||
* hints stub. malloced.
|
||||
* @param noprime: set noprime option to true or false on new hint stub.
|
||||
* @param nolock: Skip locking, locking is handled by the caller.
|
||||
* @return false on failure (out of memory);
|
||||
*/
|
||||
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
|
||||
* 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 c: class of stub zone
|
||||
* @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 */
|
||||
|
|
|
@ -1284,8 +1284,17 @@ iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd,
|
|||
uint16_t* c)
|
||||
{
|
||||
uint16_t c1 = *c, c2 = *c;
|
||||
int r1 = hints_next_root(hints, &c1);
|
||||
int r2 = forwards_next_root(fwd, &c2);
|
||||
int r1, r2;
|
||||
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 */
|
||||
return 0;
|
||||
else if(!r1) /* got one, return that */
|
||||
|
@ -1450,15 +1459,21 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp)
|
|||
|
||||
int
|
||||
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 delegpt *dp;
|
||||
int nolock = 1;
|
||||
|
||||
/* 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,
|
||||
qinf->qclass, NULL);
|
||||
dp = forwards_lookup(qstate->env->fwds, qinf->qname, qinf->qclass);
|
||||
qinf->qclass, NULL, nolock);
|
||||
dp = forwards_lookup(qstate->env->fwds, qinf->qname, qinf->qclass,
|
||||
nolock);
|
||||
|
||||
/* see if forward or stub is more pertinent */
|
||||
if(stub && stub->dp && dp) {
|
||||
|
@ -1472,7 +1487,9 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
|
|||
|
||||
/* check stub */
|
||||
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 dpname[255+1];
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
return (stub->dp->no_cache);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
return stub_no_cache;
|
||||
}
|
||||
|
||||
/* Check for forward. */
|
||||
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 dpname[255+1];
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
*retdpname = NULL;
|
||||
*retdpnamelen = 0;
|
||||
|
|
|
@ -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
|
||||
* different server and zone. You can pass NULL to not get it.
|
||||
* @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.
|
||||
*/
|
||||
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
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "iterator/iter_priv.h"
|
||||
#include "validator/val_neg.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/authzone.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 */
|
||||
static int
|
||||
can_have_last_resort(struct module_env* env, uint8_t* nm, size_t nmlen,
|
||||
uint16_t qclass, struct delegpt** retdp)
|
||||
can_have_last_resort(struct module_env* env, uint8_t* nm, size_t ATTR_UNUSED(nmlen),
|
||||
uint16_t qclass, int* have_dp, struct delegpt** retdp,
|
||||
struct regional* region)
|
||||
{
|
||||
struct delegpt* fwddp;
|
||||
struct iter_hints_stub* stub;
|
||||
int labs = dname_count_labels(nm);
|
||||
struct delegpt* dp = NULL;
|
||||
int nolock = 0;
|
||||
/* do not process a last resort (the parent side) if a stub
|
||||
* or forward is configured, because we do not want to go 'above'
|
||||
* the configured servers */
|
||||
if(!dname_is_root(nm) && (stub = (struct iter_hints_stub*)
|
||||
name_tree_find(&env->hints->tree, nm, nmlen, labs, qclass)) &&
|
||||
if(!dname_is_root(nm) &&
|
||||
(dp = hints_find(env->hints, nm, qclass, nolock)) &&
|
||||
/* has_parent side is turned off for stub_first, where we
|
||||
* are allowed to go to the parent */
|
||||
stub->dp->has_parent_side_NS) {
|
||||
if(retdp) *retdp = stub->dp;
|
||||
dp->has_parent_side_NS) {
|
||||
if(retdp) *retdp = delegpt_copy(dp, region);
|
||||
lock_rw_unlock(&env->hints->lock);
|
||||
if(have_dp) *have_dp = 1;
|
||||
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
|
||||
* we are allowed to go to the parent */
|
||||
fwddp->has_parent_side_NS) {
|
||||
if(retdp) *retdp = fwddp;
|
||||
dp->has_parent_side_NS) {
|
||||
if(retdp) *retdp = delegpt_copy(dp, region);
|
||||
lock_rw_unlock(&env->fwds->lock);
|
||||
if(have_dp) *have_dp = 1;
|
||||
return 0;
|
||||
}
|
||||
/* lock_() calls are macros that could be nothing, surround in {} */
|
||||
if(dp) { lock_rw_unlock(&env->fwds->lock); }
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -877,10 +888,11 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
|||
{
|
||||
struct delegpt* dp;
|
||||
struct module_qstate* subq;
|
||||
int nolock = 0;
|
||||
verbose(VERB_DETAIL, "priming . %s NS",
|
||||
sldns_lookup_by_id(sldns_rr_classes, (int)qclass)?
|
||||
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) {
|
||||
verbose(VERB_ALGO, "Cannot prime due to lack of hints");
|
||||
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,
|
||||
qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE,
|
||||
&subq, 0, 0)) {
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
verbose(VERB_ALGO, "could not prime root");
|
||||
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.
|
||||
* dp was part of in the fixed hints structure. */
|
||||
subiq->dp = delegpt_copy(dp, subq->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!subiq->dp) {
|
||||
log_err("out of memory priming root, copydp");
|
||||
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->dnssec_expected = iter_indicates_dnssec(
|
||||
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. */
|
||||
|
@ -941,18 +957,21 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
|
|||
struct iter_hints_stub* stub;
|
||||
struct delegpt* stub_dp;
|
||||
struct module_qstate* subq;
|
||||
int nolock = 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. */
|
||||
if(!stub)
|
||||
return 0;
|
||||
if(!stub) return 0;
|
||||
stub_dp = stub->dp;
|
||||
/* 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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/* is it a noprime stub (always use) */
|
||||
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
|
||||
* it can be changed when servicing this query */
|
||||
iq->dp = delegpt_copy(stub_dp, qstate->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!iq->dp) {
|
||||
log_err("out of memory priming stub");
|
||||
errinf(qstate, "malloc failure, priming stub");
|
||||
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
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);
|
||||
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,
|
||||
LDNS_RR_TYPE_NS, qclass, qstate, id, iq,
|
||||
QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0, 0)) {
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
verbose(VERB_ALGO, "could not prime stub");
|
||||
errinf(qstate, "could not generate lookup for stub prime");
|
||||
(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. */
|
||||
/* make copy to avoid use of stub dp by different qs/threads */
|
||||
subiq->dp = delegpt_copy(stub_dp, subq->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!subiq->dp) {
|
||||
log_err("out of memory priming stub, copydp");
|
||||
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->dnssec_expected = iter_indicates_dnssec(
|
||||
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. */
|
||||
|
@ -1181,7 +1205,7 @@ generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id)
|
|||
if(iq->depth == ie->max_dependency_depth)
|
||||
return;
|
||||
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen,
|
||||
iq->qchase.qclass, NULL))
|
||||
iq->qchase.qclass, NULL, NULL, NULL))
|
||||
return;
|
||||
/* is this query the same as the nscheck? */
|
||||
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;
|
||||
uint8_t* delname = iq->qchase.qname;
|
||||
size_t delnamelen = iq->qchase.qname_len;
|
||||
int nolock = 0;
|
||||
if(iq->refetch_glue && iq->dp) {
|
||||
delname = iq->dp->name;
|
||||
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)
|
||||
&& !dname_is_root(iq->qchase.qname))
|
||||
dname_remove_label(&delname, &delnamelen);
|
||||
dp = forwards_lookup(qstate->env->fwds, delname, iq->qchase.qclass);
|
||||
if(!dp)
|
||||
return 0;
|
||||
dp = forwards_lookup(qstate->env->fwds, delname, iq->qchase.qclass,
|
||||
nolock);
|
||||
if(!dp) return 0;
|
||||
/* send recursion desired to forward addr */
|
||||
iq->chase_flags |= BIT_RD;
|
||||
iq->dp = delegpt_copy(dp, qstate->region);
|
||||
lock_rw_unlock(&qstate->env->fwds->lock);
|
||||
/* iq->dp checked by caller */
|
||||
verbose(VERB_ALGO, "forwarding request");
|
||||
return 1;
|
||||
|
@ -1335,6 +1361,7 @@ static int
|
|||
processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
struct iter_env* ie, int id)
|
||||
{
|
||||
uint8_t dpname_storage[LDNS_MAX_DOMAINLEN+1];
|
||||
uint8_t* delname, *dpname=NULL;
|
||||
size_t delnamelen, dpnamelen=0;
|
||||
struct dns_msg* msg = NULL;
|
||||
|
@ -1381,7 +1408,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
if (iq->refetch_glue &&
|
||||
iq->dp &&
|
||||
!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;
|
||||
}
|
||||
|
||||
|
@ -1390,7 +1417,60 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
/* This either results in a query restart (CNAME cache response), a
|
||||
* 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. */
|
||||
verbose(VERB_ALGO, "no-cache set, going to the network");
|
||||
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_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
|
||||
* one. */
|
||||
iq->dp = NULL;
|
||||
|
@ -1494,7 +1541,6 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
iq->minimisation_state = INIT_MINIMISE_STATE;
|
||||
return next_state(iq, INIT_REQUEST_STATE);
|
||||
}
|
||||
|
||||
/* if from cache, NULL, else insert 'cache IP' len=0 */
|
||||
if(qstate->reply_origin)
|
||||
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 ||
|
||||
(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,
|
||||
* but only to fetch glue, not for qtype=DS. */
|
||||
/* 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. */
|
||||
if(iq->dp == NULL) {
|
||||
int r;
|
||||
int nolock = 0;
|
||||
/* if under auth zone, no prime needed */
|
||||
if(!auth_zone_delegpt(qstate, iq, delname, delnamelen))
|
||||
return error_response(qstate, id,
|
||||
|
@ -1598,11 +1645,12 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
else if(r)
|
||||
return 0; /* stub prime request made */
|
||||
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 */
|
||||
/* fill in some dp - safety belt */
|
||||
iq->dp = hints_lookup_root(qstate->env->hints,
|
||||
iq->qchase.qclass);
|
||||
iq->dp = hints_find_root(qstate->env->hints,
|
||||
iq->qchase.qclass, nolock);
|
||||
if(!iq->dp) {
|
||||
log_err("internal error: no hints dp");
|
||||
errinf(qstate, "no hints for this class");
|
||||
|
@ -1610,6 +1658,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->dp = delegpt_copy(iq->dp, qstate->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!iq->dp) {
|
||||
log_err("out of memory 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,
|
||||
iq->dp, ie->supports_ipv4, ie->supports_ipv6,
|
||||
ie->use_nat64)) {
|
||||
struct delegpt* retdp = NULL;
|
||||
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &retdp)) {
|
||||
if(retdp) {
|
||||
int have_dp = 0;
|
||||
if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &have_dp, &iq->dp, qstate->region)) {
|
||||
if(have_dp) {
|
||||
verbose(VERB_QUERY, "cache has stub "
|
||||
"or fwd but no addresses, "
|
||||
"fallback to config");
|
||||
iq->dp = delegpt_copy(retdp,
|
||||
qstate->region);
|
||||
if(!iq->dp) {
|
||||
if(have_dp && !iq->dp) {
|
||||
log_err("out of memory in "
|
||||
"stub/fwd fallback");
|
||||
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)) {
|
||||
/* use safety belt */
|
||||
int nolock = 0;
|
||||
verbose(VERB_QUERY, "Cache has root NS but "
|
||||
"no addresses. Fallback to the safety belt.");
|
||||
iq->dp = hints_lookup_root(qstate->env->hints,
|
||||
iq->qchase.qclass);
|
||||
iq->dp = hints_find_root(qstate->env->hints,
|
||||
iq->qchase.qclass, nolock);
|
||||
/* note deleg_msg is from previous lookup,
|
||||
* but RD is on, so it is not used */
|
||||
if(!iq->dp) {
|
||||
|
@ -1689,6 +1737,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
LDNS_RCODE_REFUSED);
|
||||
}
|
||||
iq->dp = delegpt_copy(iq->dp, qstate->region);
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
if(!iq->dp) {
|
||||
log_err("out of memory in safety belt");
|
||||
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;
|
||||
if(iq->refetch_glue) {
|
||||
struct iter_hints_stub* stub;
|
||||
int nolock = 0;
|
||||
if(!iq->dp) {
|
||||
log_err("internal or malloc fail: no dp for refetch");
|
||||
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. */
|
||||
stub = hints_lookup_stub(
|
||||
qstate->env->hints, iq->qchase.qname, iq->qchase.qclass,
|
||||
iq->dp);
|
||||
iq->dp, nolock);
|
||||
if(!stub || !stub->dp->has_parent_side_NS ||
|
||||
dname_subdomain_c(iq->dp->name, stub->dp->name)) {
|
||||
delname = iq->dp->name;
|
||||
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(!dname_is_root(delname))
|
||||
|
@ -2062,7 +2114,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
log_assert(iq->dp);
|
||||
|
||||
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
|
||||
* of a response. */
|
||||
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);
|
||||
}
|
||||
if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) {
|
||||
struct delegpt* p = hints_lookup_root(qstate->env->hints,
|
||||
iq->qchase.qclass);
|
||||
if(p) {
|
||||
struct delegpt* dp;
|
||||
int nolock = 0;
|
||||
dp = hints_find_root(qstate->env->hints,
|
||||
iq->qchase.qclass, nolock);
|
||||
if(dp) {
|
||||
struct delegpt_addr* a;
|
||||
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,
|
||||
ns->name, ns->lame, ns->tls_auth_name,
|
||||
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,
|
||||
&a->addr, a->addrlen, a->bogus,
|
||||
a->lame, a->tls_auth_name, -1, NULL);
|
||||
}
|
||||
lock_rw_unlock(&qstate->env->hints->lock);
|
||||
}
|
||||
iq->dp->has_parent_side_NS = 1;
|
||||
} 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) ||
|
||||
((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4)) &&
|
||||
!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 "
|
||||
"because it is also a stub/forward,",
|
||||
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);
|
||||
|
||||
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);
|
||||
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) {
|
||||
qstate->ext_state[id] = module_finished;
|
||||
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 */
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
} else if(type == RESPONSE_TYPE_CNAME &&
|
||||
}
|
||||
if(type == RESPONSE_TYPE_CNAME &&
|
||||
iq->qchase.qtype == LDNS_RR_TYPE_CNAME &&
|
||||
iq->minimisation_state == MINIMISE_STATE &&
|
||||
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);
|
||||
} else if(type == RESPONSE_TYPE_REFERRAL) {
|
||||
struct delegpt* old_dp = NULL;
|
||||
/* REFERRAL type responses get a reset of the
|
||||
* delegation point, and back to the QUERYTARGETS_STATE. */
|
||||
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
|
||||
* point to the referral. */
|
||||
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);
|
||||
if (qstate->env->cfg->qname_minimisation)
|
||||
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");
|
||||
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,
|
||||
qstate->region, iq->dp)) {
|
||||
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 */
|
||||
struct dns_msg* forged_response =
|
||||
rpz_callback_from_iterator_cname(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.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)) {
|
||||
|
@ -3926,17 +4045,9 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
!qstate->env->cfg->val_log_squelch) {
|
||||
char* err_str = errinf_to_str_misc(qstate);
|
||||
if(err_str) {
|
||||
size_t err_str_len = strlen(err_str);
|
||||
verbose(VERB_ALGO, "iterator EDE: %s", err_str);
|
||||
/* allocate space and store the error
|
||||
* string */
|
||||
iq->response->rep->reason_bogus_str = regional_alloc(
|
||||
qstate->region,
|
||||
sizeof(char) * (err_str_len+1));
|
||||
memcpy(iq->response->rep->reason_bogus_str,
|
||||
err_str, err_str_len+1);
|
||||
iq->response->rep->reason_bogus_str = err_str;
|
||||
}
|
||||
free(err_str);
|
||||
}
|
||||
|
||||
/* we have finished processing this query */
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
#include "util/storage/slabhash.h"
|
||||
#include "util/edns.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
|
||||
int
|
||||
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,
|
||||
ctx->env, &ctx->mods))
|
||||
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))
|
||||
return UB_INITFAIL;
|
||||
if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,
|
||||
|
|
|
@ -66,6 +66,8 @@
|
|||
#include "services/authzone.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
#ifdef HAVE_PTHREAD
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
@ -171,6 +173,7 @@ static struct ub_ctx* ub_ctx_create_nopipe(void)
|
|||
ctx->env->worker = NULL;
|
||||
ctx->env->need_to_validate = 0;
|
||||
modstack_init(&ctx->mods);
|
||||
ctx->env->modstack = &ctx->mods;
|
||||
rbtree_init(&ctx->queries, &context_query_cmp);
|
||||
return ctx;
|
||||
}
|
||||
|
@ -379,6 +382,8 @@ ub_ctx_delete(struct ub_ctx* ctx)
|
|||
config_delete(ctx->env->cfg);
|
||||
edns_known_options_delete(ctx->env);
|
||||
edns_strings_delete(ctx->env->edns_strings);
|
||||
forwards_delete(ctx->env->fwds);
|
||||
hints_delete(ctx->env->hints);
|
||||
auth_zones_delete(ctx->env->auth_zones);
|
||||
free(ctx->env);
|
||||
}
|
||||
|
|
|
@ -70,8 +70,6 @@
|
|||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/tube.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
#include "sldns/str2wire.h"
|
||||
#ifdef USE_DNSTAP
|
||||
|
@ -100,8 +98,6 @@ libworker_delete_env(struct libworker* w)
|
|||
!w->is_bg || w->is_bg_thread);
|
||||
sldns_buffer_free(w->env->scratch_buffer);
|
||||
regional_destroy(w->env->scratch);
|
||||
forwards_delete(w->env->fwds);
|
||||
hints_delete(w->env->hints);
|
||||
ub_randfree(w->env->rnd);
|
||||
free(w->env);
|
||||
}
|
||||
|
@ -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_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
|
||||
w->sslctx = connect_sslctx_create(NULL, NULL,
|
||||
cfg->tls_cert_bundle, cfg->tls_win_cert);
|
||||
if(!w->sslctx) {
|
||||
/* to make the setup fail after unlock */
|
||||
hints_delete(w->env->hints);
|
||||
w->env->hints = NULL;
|
||||
sldns_buffer_free(w->env->scratch_buffer);
|
||||
w->env->scratch_buffer = NULL;
|
||||
}
|
||||
#endif
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds ||
|
||||
!w->env->hints) {
|
||||
if(!w->env->scratch || !w->env->scratch_buffer) {
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -2152,6 +2152,16 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c)
|
|||
if(az->rpz_first)
|
||||
az->rpz_first->rpz_az_prev = 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) {
|
||||
lock_rw_unlock(&az->rpz_lock);
|
||||
|
|
52
usr.sbin/unbound/services/cache/dns.c
vendored
52
usr.sbin/unbound/services/cache/dns.c
vendored
|
@ -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);
|
||||
}
|
||||
|
||||
/** 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) */
|
||||
static struct ub_packed_rrset_key*
|
||||
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
|
||||
* for the lock ordering */
|
||||
lock_rw_unlock(&rrset->entry.lock);
|
||||
/* the expired_above function always takes off one
|
||||
* label (if qnamelen>0) and returns the final qname
|
||||
* where it searched, so we can continue from there
|
||||
* turning the O N*N search into O N. */
|
||||
if(!rrset_expired_above(env, &qname, &qnamelen,
|
||||
searchtype, qclass, now, expiretop,
|
||||
/* the rrset_cache_expired_above function always takes
|
||||
* off one label (if qnamelen>0) and returns the final
|
||||
* qname where it searched, so we can continue from
|
||||
* there turning the O N*N search into O N. */
|
||||
if(!rrset_cache_expired_above(env->rrset_cache, &qname,
|
||||
&qnamelen, searchtype, qclass, now, expiretop,
|
||||
expiretoplen)) {
|
||||
/* we want to return rrset, but it may be
|
||||
* gone from cache, if so, just loop like
|
||||
|
|
170
usr.sbin/unbound/services/cache/infra.c
vendored
170
usr.sbin/unbound/services/cache/infra.c
vendored
|
@ -234,6 +234,81 @@ setup_domain_limits(struct infra_cache* infra, struct config_file* cfg)
|
|||
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*
|
||||
infra_create(struct config_file* cfg)
|
||||
{
|
||||
|
@ -267,6 +342,10 @@ infra_create(struct config_file* cfg)
|
|||
infra_delete(infra);
|
||||
return NULL;
|
||||
}
|
||||
if(!setup_wait_limits(infra, cfg)) {
|
||||
infra_delete(infra);
|
||||
return NULL;
|
||||
}
|
||||
infra_ip_ratelimit = cfg->ip_ratelimit;
|
||||
infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs,
|
||||
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
|
||||
infra_delete(struct infra_cache* infra)
|
||||
{
|
||||
|
@ -296,6 +381,10 @@ infra_delete(struct infra_cache* infra)
|
|||
slabhash_delete(infra->domain_rates);
|
||||
traverse_postorder(&infra->domain_limits, domain_limit_free, NULL);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -880,7 +969,8 @@ static void infra_create_ratedata(struct infra_cache* infra,
|
|||
|
||||
/** create rate data item for ip address */
|
||||
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);
|
||||
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;
|
||||
d->qps[0] = 1;
|
||||
d->timestamp[0] = timenow;
|
||||
d->mesh_wait = mesh_wait;
|
||||
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 */
|
||||
infra_ip_create_ratedata(infra, addr, addrlen, timenow);
|
||||
infra_ip_create_ratedata(infra, addr, addrlen, timenow, 0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
28
usr.sbin/unbound/services/cache/infra.h
vendored
28
usr.sbin/unbound/services/cache/infra.h
vendored
|
@ -122,6 +122,10 @@ struct infra_cache {
|
|||
rbtree_type domain_limits;
|
||||
/** hash table with query rates per client ip: ip_rate_key, ip_rate_data */
|
||||
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 */
|
||||
|
@ -184,10 +188,22 @@ struct rate_data {
|
|||
/** what the timestamp is of the qps array members, counter is
|
||||
* valid for that timestamp. Usually now and now-1. */
|
||||
time_t timestamp[RATE_WINDOW];
|
||||
/** the number of queries waiting in the mesh */
|
||||
int mesh_wait;
|
||||
};
|
||||
|
||||
#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 */
|
||||
#define INFRA_HOST_STARTSIZE 32
|
||||
/** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */
|
||||
|
@ -474,4 +490,16 @@ void ip_rate_delkeyfunc(void* d, void* arg);
|
|||
/* delete data */
|
||||
#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 */
|
||||
|
|
87
usr.sbin/unbound/services/cache/rrset.c
vendored
87
usr.sbin/unbound/services/cache/rrset.c
vendored
|
@ -46,6 +46,7 @@
|
|||
#include "util/data/packed_rrset.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/alloc.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* 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
|
||||
* everything better than bogus data
|
||||
* secure is preferred */
|
||||
|
@ -440,6 +444,89 @@ rrset_check_sec_status(struct rrset_cache* r,
|
|||
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,
|
||||
uint16_t type, uint16_t dclass, uint32_t flags)
|
||||
{
|
||||
|
|
31
usr.sbin/unbound/services/cache/rrset.h
vendored
31
usr.sbin/unbound/services/cache/rrset.h
vendored
|
@ -231,6 +231,37 @@ void rrset_update_sec_status(struct rrset_cache* r,
|
|||
void rrset_check_sec_status(struct rrset_cache* r,
|
||||
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
|
||||
* @param r: rrset cache
|
||||
|
|
|
@ -140,9 +140,11 @@ void
|
|||
verbose_print_unbound_socket(struct unbound_socket* ub_sock)
|
||||
{
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
char buf[256];
|
||||
log_info("listing of unbound_socket structure:");
|
||||
verbose_print_addr(ub_sock->addr);
|
||||
log_info("s is: %d, fam is: %s, acl: %s", ub_sock->s,
|
||||
addr_to_str((void*)ub_sock->addr, ub_sock->addrlen, buf,
|
||||
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->acl?"yes":"no");
|
||||
}
|
||||
|
@ -610,7 +612,9 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
|
|||
# elif defined(IP_DONTFRAG) && !defined(__APPLE__)
|
||||
/* the IP_DONTFRAG option if defined in the 11.0 OSX headers,
|
||||
* 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,
|
||||
&off, (socklen_t)sizeof(off)) < 0) {
|
||||
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->fam = hints->ai_family;
|
||||
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,
|
||||
&noip6, rcv, snd, reuseport, transparent,
|
||||
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) {
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
if(noip6) {
|
||||
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 */
|
||||
if(!set_recvpktinfo(s, hints->ai_family)) {
|
||||
sock_close(s);
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
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,
|
||||
is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
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,
|
||||
&noip6, rcv, snd, reuseport, transparent,
|
||||
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) {
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
if(noip6) {
|
||||
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),
|
||||
is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
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,
|
||||
&noip6, 0, 0, reuseport, transparent, tcp_mss, nodelay,
|
||||
freebind, use_systemd, dscp, ub_sock)) == -1) {
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
if(noip6) {
|
||||
/*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");
|
||||
if(!port_insert(list, s, port_type, is_pp2, ub_sock)) {
|
||||
sock_close(s);
|
||||
if(ub_sock->addr)
|
||||
freeaddrinfo(ub_sock->addr);
|
||||
free(ub_sock->addr);
|
||||
free(ub_sock);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1952,8 +1964,7 @@ void listening_ports_free(struct listen_port* list)
|
|||
}
|
||||
/* rc_ports don't have ub_socket */
|
||||
if(list->socket) {
|
||||
if(list->socket->addr)
|
||||
freeaddrinfo(list->socket->addr);
|
||||
free(list->socket->addr);
|
||||
free(list->socket);
|
||||
}
|
||||
free(list);
|
||||
|
|
|
@ -107,11 +107,13 @@ enum listen_type {
|
|||
* socket properties (just like NSD nsd_socket structure definition)
|
||||
*/
|
||||
struct unbound_socket {
|
||||
/** socket-address structure */
|
||||
struct addrinfo* addr;
|
||||
/** the address of the socket */
|
||||
struct sockaddr* addr;
|
||||
/** length of the address */
|
||||
socklen_t addrlen;
|
||||
/** socket descriptor returned by socket() syscall */
|
||||
int s;
|
||||
/** address family (AF_INET/IF_INET6) */
|
||||
/** address family (AF_INET/AF_INET6) */
|
||||
int fam;
|
||||
/** ACL on the socket (listening interface) */
|
||||
struct acl_addr* acl;
|
||||
|
|
|
@ -330,14 +330,16 @@ get_rr_nameclass(const char* str, uint8_t** nm, uint16_t* dclass,
|
|||
static struct local_rrset*
|
||||
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);
|
||||
for(p = data->rrsets; p; p = p->next) {
|
||||
if(p->rrset->rk.type == type)
|
||||
return p;
|
||||
if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
|
||||
return p;
|
||||
cname = p;
|
||||
}
|
||||
if(alias_ok)
|
||||
return cname;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "services/outbound_list.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/module.h"
|
||||
|
@ -385,7 +386,7 @@ mesh_serve_expired_init(struct mesh_state* mstate, int timeout)
|
|||
&mesh_serve_expired_lookup;
|
||||
|
||||
/* 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.env->worker_base, mesh_serve_expired_callback, mstate);
|
||||
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) {
|
||||
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)
|
||||
s = mesh_area_find(mesh, cinfo, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||
/* 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");
|
||||
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 */
|
||||
if(was_detached) {
|
||||
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);
|
||||
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 */
|
||||
if(was_detached) {
|
||||
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 */
|
||||
mstate->reply_list = NULL;
|
||||
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);
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
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;
|
||||
if(!rcode && rep && (rep->security == sec_status_bogus ||
|
||||
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;
|
||||
}
|
||||
/* 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);
|
||||
m->reply_list = rlist;
|
||||
}
|
||||
infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply,
|
||||
m->s.env->cfg);
|
||||
/* account */
|
||||
log_assert(m->s.env->mesh->num_reply_addrs > 0);
|
||||
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,
|
||||
&r->query_reply.client_addr,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1464,12 +1502,32 @@ void mesh_query_done(struct mesh_state* mstate)
|
|||
&& mstate->s.env->cfg->log_servfail
|
||||
&& !mstate->s.env->cfg->val_log_squelch) {
|
||||
char* err = errinf_to_str_servfail(&mstate->s);
|
||||
if(err)
|
||||
log_err("%s", err);
|
||||
free(err);
|
||||
if(err) { log_err("%s", err); }
|
||||
}
|
||||
}
|
||||
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++;
|
||||
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
|
||||
* done there, but instead we do that here. */
|
||||
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;
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
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 */
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
infra_wait_limit_dec(mesh->env->infra_cache,
|
||||
&n->query_reply, mesh->env->cfg);
|
||||
|
||||
/* prev = prev; */
|
||||
n = n->next;
|
||||
|
@ -2165,6 +2227,28 @@ mesh_serve_expired_callback(void* arg)
|
|||
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
|
||||
|
||||
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++;
|
||||
tv = r->start_time;
|
||||
|
||||
|
@ -2192,6 +2276,8 @@ mesh_serve_expired_callback(void* arg)
|
|||
r, r_buffer, prev, prev_buffer);
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
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_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)
|
||||
{
|
||||
if(mesh->all.count < mesh->max_reply_states)
|
||||
|
|
|
@ -690,4 +690,10 @@ mesh_serve_expired_lookup(struct module_qstate* qstate,
|
|||
*/
|
||||
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 */
|
||||
|
|
|
@ -478,6 +478,67 @@ new_cname_override(struct regional* region, uint8_t* ct, size_t ctlen)
|
|||
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*
|
||||
rpz_create(struct config_auth* p)
|
||||
{
|
||||
|
@ -513,42 +574,8 @@ rpz_create(struct config_auth* p)
|
|||
goto err;
|
||||
}
|
||||
|
||||
r->taglistlen = p->rpz_taglistlen;
|
||||
r->taglist = memdup(p->rpz_taglist, r->taglistlen);
|
||||
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;
|
||||
}
|
||||
}
|
||||
if(!rpz_apply_cfg_elements(r, p))
|
||||
goto err;
|
||||
return r;
|
||||
err:
|
||||
if(r) {
|
||||
|
@ -571,6 +598,32 @@ err:
|
|||
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
|
||||
* 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. */
|
||||
static struct local_rrset*
|
||||
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) {
|
||||
struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
|
||||
if(htons(qtype) == packed_rrset->type) {
|
||||
return cursor;
|
||||
}
|
||||
if(ntohs(packed_rrset->type) == LDNS_RR_TYPE_CNAME && alias_ok)
|
||||
cname = cursor;
|
||||
cursor = cursor->next;
|
||||
}
|
||||
if(alias_ok)
|
||||
return cname;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1386,7 +1443,7 @@ static int rpz_remove_clientip_rr(struct clientip_synthesized_rr* node,
|
|||
struct local_rrset* rrset;
|
||||
struct packed_rrset_data* d;
|
||||
size_t index;
|
||||
rrset = rpz_find_synthesized_rrset(rr_type, node);
|
||||
rrset = rpz_find_synthesized_rrset(rr_type, node, 0);
|
||||
if(rrset == NULL)
|
||||
return 0; /* type not found, ignore */
|
||||
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 */
|
||||
rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr);
|
||||
rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr, 1);
|
||||
if(rrset == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: unable to find local-data for query");
|
||||
rrset_count = 0;
|
||||
|
@ -1823,6 +1880,28 @@ nodata:
|
|||
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.
|
||||
* Since this gets fed into the normal iterator answer creation, it
|
||||
* 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);
|
||||
if(msg == NULL) { return NULL; }
|
||||
|
||||
msg->qinfo = *qi;
|
||||
new_reply_info = construct_reply_info_base(ms->region,
|
||||
LDNS_RCODE_NOERROR | BIT_QR | BIT_AA | BIT_RA,
|
||||
1, /* qd */
|
||||
|
@ -1975,40 +2055,42 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs
|
|||
|
||||
static inline struct dns_msg*
|
||||
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;
|
||||
|
||||
rrset = rpz_find_synthesized_rrset(qi->qtype, data);
|
||||
rrset = rpz_find_synthesized_rrset(qi->qtype, data, 1);
|
||||
if(rrset == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: nsip: no matching local data found");
|
||||
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 */
|
||||
static struct local_rrset*
|
||||
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);
|
||||
for(p = data->rrsets; p; p = p->next) {
|
||||
if(p->rrset->rk.type == type)
|
||||
return p;
|
||||
if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
|
||||
return p;
|
||||
cname = p;
|
||||
}
|
||||
if(alias_ok)
|
||||
return cname;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* based on localzone.c:local_data_answer() */
|
||||
static inline struct dns_msg*
|
||||
rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
|
||||
struct local_zone* z, struct matched_delegation_point const* match,
|
||||
struct auth_zone* az)
|
||||
struct query_info* qi, struct local_zone* z,
|
||||
struct matched_delegation_point const* match, struct auth_zone* az)
|
||||
{
|
||||
struct local_data key;
|
||||
struct local_data* ld;
|
||||
|
@ -2029,13 +2111,13 @@ rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
rrset = local_data_find_type(ld, ms->qinfo.qtype, 1);
|
||||
rrset = local_data_find_type(ld, qi->qtype, 1);
|
||||
if(rrset == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: nsdname: no matching local data found");
|
||||
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 */
|
||||
|
@ -2052,17 +2134,70 @@ rpz_synthesize_qname_localdata_msg(struct rpz* r, struct module_qstate* ms,
|
|||
key.namelabs = dname_count_labels(qinfo->qname);
|
||||
ld = (struct local_data*)rbtree_search(&z->data, &key.node);
|
||||
if(ld == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: qname after cname: name not found");
|
||||
verbose(VERB_ALGO, "rpz: qname: name not found");
|
||||
return NULL;
|
||||
}
|
||||
rrset = local_data_find_type(ld, qinfo->qtype, 1);
|
||||
if(rrset == NULL) {
|
||||
verbose(VERB_ALGO, "rpz: qname after cname: type not found");
|
||||
verbose(VERB_ALGO, "rpz: qname: type not found");
|
||||
return NULL;
|
||||
}
|
||||
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
|
||||
rpz_synthesize_qname_localdata(struct module_env* env, struct rpz* r,
|
||||
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;
|
||||
int ret = 0;
|
||||
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
|
||||
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 = 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(!rpz_apply_cname_override_action(r, qinfo, temp))
|
||||
return 0;
|
||||
if(r->log) {
|
||||
log_rpz_apply("qname", z->name, NULL, RPZ_CNAME_OVERRIDE_ACTION,
|
||||
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*
|
||||
rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
|
||||
struct clientip_synthesized_rr* raddr, struct auth_zone* az)
|
||||
rpz_apply_nsip_trigger(struct module_qstate* ms, struct query_info* qchase,
|
||||
struct rpz* r, struct clientip_synthesized_rr* raddr,
|
||||
struct auth_zone* az)
|
||||
{
|
||||
enum rpz_action action = raddr->action;
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
switch(action) {
|
||||
case RPZ_NXDOMAIN_ACTION:
|
||||
ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nxdomain(r, ms, qchase, az);
|
||||
break;
|
||||
case RPZ_NODATA_ACTION:
|
||||
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nodata(r, ms, qchase, az);
|
||||
break;
|
||||
case RPZ_TCP_ONLY_ACTION:
|
||||
/* 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;
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
case RPZ_LOCAL_DATA_ACTION:
|
||||
ret = rpz_synthesize_nsip_localdata(r, ms, raddr, az);
|
||||
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); }
|
||||
ret = rpz_synthesize_nsip_localdata(r, ms, qchase, raddr, az);
|
||||
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); }
|
||||
break;
|
||||
case RPZ_PASSTHRU_ACTION:
|
||||
ret = NULL;
|
||||
ms->rpz_passthru = 1;
|
||||
break;
|
||||
case RPZ_CNAME_OVERRIDE_ACTION:
|
||||
ret = rpz_synthesize_cname_override_msg(r, ms, qchase);
|
||||
break;
|
||||
default:
|
||||
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
|
||||
rpz_action_to_string(action));
|
||||
|
@ -2194,9 +2324,9 @@ done:
|
|||
}
|
||||
|
||||
static struct dns_msg*
|
||||
rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
|
||||
struct local_zone* z, struct matched_delegation_point const* match,
|
||||
struct auth_zone* az)
|
||||
rpz_apply_nsdname_trigger(struct module_qstate* ms, struct query_info* qchase,
|
||||
struct rpz* r, struct local_zone* z,
|
||||
struct matched_delegation_point const* match, struct auth_zone* az)
|
||||
{
|
||||
struct dns_msg* ret = NULL;
|
||||
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) {
|
||||
case RPZ_NXDOMAIN_ACTION:
|
||||
ret = rpz_synthesize_nxdomain(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nxdomain(r, ms, qchase, az);
|
||||
break;
|
||||
case RPZ_NODATA_ACTION:
|
||||
ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az);
|
||||
ret = rpz_synthesize_nodata(r, ms, qchase, az);
|
||||
break;
|
||||
case RPZ_TCP_ONLY_ACTION:
|
||||
/* 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;
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
case RPZ_LOCAL_DATA_ACTION:
|
||||
ret = rpz_synthesize_nsdname_localdata(r, ms, z, match, az);
|
||||
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, &ms->qinfo, az); }
|
||||
ret = rpz_synthesize_nsdname_localdata(r, ms, qchase, z, match, az);
|
||||
if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms, qchase, az); }
|
||||
break;
|
||||
case RPZ_PASSTHRU_ACTION:
|
||||
ret = NULL;
|
||||
ms->rpz_passthru = 1;
|
||||
break;
|
||||
case RPZ_CNAME_OVERRIDE_ACTION:
|
||||
ret = rpz_synthesize_cname_override_msg(r, ms, qchase);
|
||||
break;
|
||||
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));
|
||||
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 */
|
||||
z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones,
|
||||
ms->qinfo.qclass, &match);
|
||||
is->qchase.qclass, &match);
|
||||
if(z != NULL) {
|
||||
lock_rw_unlock(&a->lock);
|
||||
break;
|
||||
|
@ -2347,9 +2480,9 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
|||
if(z) {
|
||||
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,
|
||||
|
@ -2412,10 +2545,10 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
|
|||
dname_str(is->qchase.qname, nm);
|
||||
dname_str(z->name, zn);
|
||||
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)));
|
||||
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)));
|
||||
}
|
||||
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;
|
||||
break;
|
||||
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)));
|
||||
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);
|
||||
|
||||
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(*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;
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
if(*z_out == NULL || (client_action != RPZ_INVALID_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) {
|
||||
rpz_apply_clientip_localdata_action(node, env, qinfo,
|
||||
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 {
|
||||
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,
|
||||
repinfo, buf, temp, 0 /* no local data used */,
|
||||
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_NXDOMAIN)
|
||||
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;
|
||||
}
|
||||
ret = -1;
|
||||
|
|
|
@ -225,6 +225,14 @@ int rpz_clear(struct rpz* r);
|
|||
*/
|
||||
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
|
||||
* @param a: RPZ action to get string for
|
||||
|
|
|
@ -126,7 +126,8 @@ void view_delete(struct view* v);
|
|||
*/
|
||||
void views_print(struct views* v);
|
||||
|
||||
/* Find a view by name.
|
||||
/**
|
||||
* Find a view by name.
|
||||
* @param vs: views
|
||||
* @param name: name of the view we are looking for
|
||||
* @param write: 1 for obtaining write lock on found view, 0 for read lock
|
||||
|
|
|
@ -1839,15 +1839,49 @@ verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust, const char* p7signer)
|
|||
return secure;
|
||||
}
|
||||
|
||||
/** open a temp file */
|
||||
static FILE*
|
||||
tempfile_open(char* tempf, size_t tempflen, const char* fname, const char* mode)
|
||||
{
|
||||
snprintf(tempf, tempflen, "%s~", fname);
|
||||
return fopen(tempf, mode);
|
||||
}
|
||||
|
||||
/** close an open temp file and replace the original with it */
|
||||
static void
|
||||
tempfile_close(FILE* fd, const char* tempf, const char* fname)
|
||||
{
|
||||
fflush(fd);
|
||||
#ifdef HAVE_FSYNC
|
||||
fsync(fileno(fd));
|
||||
#else
|
||||
FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(fd)));
|
||||
#endif
|
||||
if(fclose(fd) != 0) {
|
||||
printf("could not complete write: %s: %s\n",
|
||||
tempf, strerror(errno));
|
||||
unlink(tempf);
|
||||
return;
|
||||
}
|
||||
/* success; overwrite actual file */
|
||||
#ifdef USE_WINSOCK
|
||||
(void)unlink(fname); /* windows does not replace file with rename() */
|
||||
#endif
|
||||
if(rename(tempf, fname) < 0) {
|
||||
printf("rename(%s to %s): %s", tempf, fname, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/** write unsigned root anchor file, a 5011 revoked tp */
|
||||
static void
|
||||
write_unsigned_root(const char* root_anchor_file)
|
||||
{
|
||||
FILE* out;
|
||||
time_t now = time(NULL);
|
||||
out = fopen(root_anchor_file, "w");
|
||||
char tempf[2048];
|
||||
out = tempfile_open(tempf, sizeof(tempf), root_anchor_file, "w");
|
||||
if(!out) {
|
||||
if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno));
|
||||
if(verb) printf("%s: %s\n", tempf, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if(fprintf(out, "; autotrust trust anchor file\n"
|
||||
|
@ -1862,13 +1896,7 @@ write_unsigned_root(const char* root_anchor_file)
|
|||
root_anchor_file);
|
||||
if(verb && errno != 0) printf("%s\n", strerror(errno));
|
||||
}
|
||||
fflush(out);
|
||||
#ifdef HAVE_FSYNC
|
||||
fsync(fileno(out));
|
||||
#else
|
||||
FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out)));
|
||||
#endif
|
||||
fclose(out);
|
||||
tempfile_close(out, tempf, root_anchor_file);
|
||||
}
|
||||
|
||||
/** write root anchor file */
|
||||
|
@ -1878,29 +1906,24 @@ write_root_anchor(const char* root_anchor_file, BIO* ds)
|
|||
char* pp = NULL;
|
||||
int len;
|
||||
FILE* out;
|
||||
char tempf[2048];
|
||||
(void)BIO_seek(ds, 0);
|
||||
len = BIO_get_mem_data(ds, &pp);
|
||||
if(!len || !pp) {
|
||||
if(verb) printf("out of memory\n");
|
||||
return;
|
||||
}
|
||||
out = fopen(root_anchor_file, "w");
|
||||
out = tempfile_open(tempf, sizeof(tempf), root_anchor_file, "w");
|
||||
if(!out) {
|
||||
if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno));
|
||||
if(verb) printf("%s: %s\n", tempf, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if(fwrite(pp, (size_t)len, 1, out) != 1) {
|
||||
if(verb) printf("failed to write all data to %s\n",
|
||||
root_anchor_file);
|
||||
tempf);
|
||||
if(verb && errno != 0) printf("%s\n", strerror(errno));
|
||||
}
|
||||
fflush(out);
|
||||
#ifdef HAVE_FSYNC
|
||||
fsync(fileno(out));
|
||||
#else
|
||||
FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out)));
|
||||
#endif
|
||||
fclose(out);
|
||||
tempfile_close(out, tempf, root_anchor_file);
|
||||
}
|
||||
|
||||
/** Perform the verification and update of the trustanchor file */
|
||||
|
@ -2044,18 +2067,19 @@ try_read_anchor(const char* file)
|
|||
static void
|
||||
write_builtin_anchor(const char* file)
|
||||
{
|
||||
char tempf[2048];
|
||||
const char* builtin_root_anchor = get_builtin_ds();
|
||||
FILE* out = fopen(file, "w");
|
||||
FILE* out = tempfile_open(tempf, sizeof(tempf), file, "w");
|
||||
if(!out) {
|
||||
printf("could not write builtin anchor, to file %s: %s\n",
|
||||
file, strerror(errno));
|
||||
tempf, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if(!fwrite(builtin_root_anchor, strlen(builtin_root_anchor), 1, out)) {
|
||||
printf("could not complete write builtin anchor, to file %s: %s\n",
|
||||
file, strerror(errno));
|
||||
tempf, strerror(errno));
|
||||
}
|
||||
fclose(out);
|
||||
tempfile_close(out, tempf, file);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -88,6 +88,7 @@ usage(void)
|
|||
printf("file if omitted %s is used.\n", CONFIGFILE);
|
||||
printf("-o option print value of option to stdout.\n");
|
||||
printf("-f output full pathname with chroot applied, eg. with -o pidfile.\n");
|
||||
printf("-q quiet (suppress output on success).\n");
|
||||
printf("-h show this usage help.\n");
|
||||
printf("Version %s\n", PACKAGE_VERSION);
|
||||
printf("BSD licensed, see LICENSE in source package for details.\n");
|
||||
|
@ -969,7 +970,7 @@ check_auth(struct config_file* cfg)
|
|||
|
||||
/** check config file */
|
||||
static void
|
||||
checkconf(const char* cfgfile, const char* opt, int final)
|
||||
checkconf(const char* cfgfile, const char* opt, int final, int quiet)
|
||||
{
|
||||
char oldwd[4096];
|
||||
struct config_file* cfg = config_create();
|
||||
|
@ -1002,7 +1003,7 @@ checkconf(const char* cfgfile, const char* opt, int final)
|
|||
check_fwd(cfg);
|
||||
check_hints(cfg);
|
||||
check_auth(cfg);
|
||||
printf("unbound-checkconf: no errors in %s\n", cfgfile);
|
||||
if(!quiet) { printf("unbound-checkconf: no errors in %s\n", cfgfile); }
|
||||
config_delete(cfg);
|
||||
}
|
||||
|
||||
|
@ -1016,6 +1017,7 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
int c;
|
||||
int final = 0;
|
||||
int quiet = 0;
|
||||
const char* f;
|
||||
const char* opt = NULL;
|
||||
const char* cfgfile = CONFIGFILE;
|
||||
|
@ -1028,7 +1030,7 @@ int main(int argc, char* argv[])
|
|||
cfgfile = CONFIGFILE;
|
||||
#endif /* USE_WINSOCK */
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "fho:")) != -1) {
|
||||
while( (c=getopt(argc, argv, "fhqo:")) != -1) {
|
||||
switch(c) {
|
||||
case 'f':
|
||||
final = 1;
|
||||
|
@ -1036,6 +1038,9 @@ int main(int argc, char* argv[])
|
|||
case 'o':
|
||||
opt = optarg;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
|
@ -1053,7 +1058,7 @@ int main(int argc, char* argv[])
|
|||
if (pledge("stdio rpath dns getpw", NULL) == -1)
|
||||
fatal_exit("Could not pledge");
|
||||
|
||||
checkconf(f, opt, final);
|
||||
checkconf(f, opt, final, quiet);
|
||||
checklock_stop();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -150,12 +150,13 @@ usage(void)
|
|||
printf(" list_local_data list local-data RRs in use\n");
|
||||
printf(" insecure_add zone add domain-insecure zone\n");
|
||||
printf(" insecure_remove zone remove domain-insecure zone\n");
|
||||
printf(" forward_add [+i] zone addr.. add forward-zone with servers\n");
|
||||
printf(" forward_add [+it] zone addr.. add forward-zone with servers\n");
|
||||
printf(" forward_remove [+i] zone remove forward zone\n");
|
||||
printf(" stub_add [+ip] zone addr.. add stub-zone with servers\n");
|
||||
printf(" stub_add [+ipt] zone addr.. add stub-zone with servers\n");
|
||||
printf(" stub_remove [+i] zone remove stub zone\n");
|
||||
printf(" +i also do dnssec insecure point\n");
|
||||
printf(" +p set stub to use priming\n");
|
||||
printf(" +t set to use tls upstream\n");
|
||||
printf(" forward [off | addr ...] without arg show forward setup\n");
|
||||
printf(" or off to turn off root forwarding\n");
|
||||
printf(" or give list of ip addresses\n");
|
||||
|
|
|
@ -68,6 +68,17 @@ static struct thr_check* thread_infos[THRDEBUG_MAX_THREADS];
|
|||
int check_locking_order = 1;
|
||||
/** the pid of this runset, reasonably unique. */
|
||||
static pid_t check_lock_pid;
|
||||
/**
|
||||
* Should checklocks print a trace of the lock and unlock calls.
|
||||
* It uses fprintf for that because the log function uses a lock and that
|
||||
* would loop otherwise.
|
||||
*/
|
||||
static int verbose_locking = 0;
|
||||
/**
|
||||
* Assume lock 0 0 (create_thread, create_instance), is the log lock and
|
||||
* do not print for that. Otherwise the output is full of log lock accesses.
|
||||
*/
|
||||
static int verbose_locking_not_loglock = 1;
|
||||
|
||||
/** print all possible debug info on the state of the system */
|
||||
static void total_debug_info(void);
|
||||
|
@ -508,6 +519,9 @@ checklock_rdlock(enum check_lock_type type, struct checked_lock* lock,
|
|||
if(key_deleted)
|
||||
return;
|
||||
|
||||
if(verbose_locking && !(verbose_locking_not_loglock &&
|
||||
lock->create_thread == 0 && lock->create_instance == 0))
|
||||
fprintf(stderr, "checklock_rdlock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line);
|
||||
log_assert(type == check_lock_rwlock);
|
||||
checklock_lockit(type, lock, func, file, line,
|
||||
try_rd, timed_rd, &lock->u.rwlock, 0, 0);
|
||||
|
@ -528,6 +542,9 @@ checklock_wrlock(enum check_lock_type type, struct checked_lock* lock,
|
|||
if(key_deleted)
|
||||
return;
|
||||
log_assert(type == check_lock_rwlock);
|
||||
if(verbose_locking && !(verbose_locking_not_loglock &&
|
||||
lock->create_thread == 0 && lock->create_instance == 0))
|
||||
fprintf(stderr, "checklock_wrlock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line);
|
||||
checklock_lockit(type, lock, func, file, line,
|
||||
try_wr, timed_wr, &lock->u.rwlock, 0, 1);
|
||||
}
|
||||
|
@ -565,6 +582,9 @@ checklock_lock(enum check_lock_type type, struct checked_lock* lock,
|
|||
if(key_deleted)
|
||||
return;
|
||||
log_assert(type != check_lock_rwlock);
|
||||
if(verbose_locking && !(verbose_locking_not_loglock &&
|
||||
lock->create_thread == 0 && lock->create_instance == 0))
|
||||
fprintf(stderr, "checklock_lock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line);
|
||||
switch(type) {
|
||||
case check_lock_mutex:
|
||||
checklock_lockit(type, lock, func, file, line,
|
||||
|
@ -602,6 +622,10 @@ checklock_unlock(enum check_lock_type type, struct checked_lock* lock,
|
|||
if(lock->hold_count <= 0)
|
||||
lock_error(lock, func, file, line, "too many unlocks");
|
||||
|
||||
if(verbose_locking && !(verbose_locking_not_loglock &&
|
||||
lock->create_thread == 0 && lock->create_instance == 0))
|
||||
fprintf(stderr, "checklock_unlock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line);
|
||||
|
||||
/* store this point as last touched by */
|
||||
lock->holder = thr;
|
||||
lock->hold_count --;
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "util/edns.h"
|
||||
#include "util/config_file.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
|
@ -65,6 +66,7 @@
|
|||
#include "sldns/wire2str.h"
|
||||
#include "sldns/str2wire.h"
|
||||
#include "daemon/remote.h"
|
||||
#include "daemon/daemon.h"
|
||||
#include "util/timeval_func.h"
|
||||
#include <signal.h>
|
||||
struct worker;
|
||||
|
@ -154,6 +156,8 @@ repevt_string(enum replay_event_type t)
|
|||
case repevt_assign: return "ASSIGN";
|
||||
case repevt_traffic: return "TRAFFIC";
|
||||
case repevt_infra_rtt: return "INFRA_RTT";
|
||||
case repevt_flush_message: return "FLUSH_MESSAGE";
|
||||
case repevt_expire_message: return "EXPIRE_MESSAGE";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
@ -691,6 +695,66 @@ do_infra_rtt(struct replay_runtime* runtime)
|
|||
free(dp);
|
||||
}
|
||||
|
||||
/** Flush message from message cache. */
|
||||
static void
|
||||
do_flush_message(struct replay_runtime* runtime)
|
||||
{
|
||||
struct replay_moment* now = runtime->now;
|
||||
uint8_t rr[1024];
|
||||
size_t rr_len = sizeof(rr), dname_len = 0;
|
||||
hashvalue_type h;
|
||||
struct query_info k;
|
||||
|
||||
if(sldns_str2wire_rr_question_buf(now->string, rr, &rr_len,
|
||||
&dname_len, NULL, 0, NULL, 0) != 0)
|
||||
fatal_exit("could not parse '%s'", now->string);
|
||||
|
||||
log_info("remove message %s", now->string);
|
||||
k.qname = rr;
|
||||
k.qname_len = dname_len;
|
||||
k.qtype = sldns_wirerr_get_type(rr, rr_len, dname_len);
|
||||
k.qclass = sldns_wirerr_get_class(rr, rr_len, dname_len);
|
||||
k.local_alias = NULL;
|
||||
h = query_info_hash(&k, 0);
|
||||
slabhash_remove(runtime->daemon->env->msg_cache, h, &k);
|
||||
}
|
||||
|
||||
/** Expire message from message cache. */
|
||||
static void
|
||||
do_expire_message(struct replay_runtime* runtime)
|
||||
{
|
||||
struct replay_moment* now = runtime->now;
|
||||
uint8_t rr[1024];
|
||||
size_t rr_len = sizeof(rr), dname_len = 0;
|
||||
hashvalue_type h;
|
||||
struct query_info k;
|
||||
struct lruhash_entry* e;
|
||||
|
||||
if(sldns_str2wire_rr_question_buf(now->string, rr, &rr_len,
|
||||
&dname_len, NULL, 0, NULL, 0) != 0)
|
||||
fatal_exit("could not parse '%s'", now->string);
|
||||
|
||||
log_info("expire message %s", now->string);
|
||||
k.qname = rr;
|
||||
k.qname_len = dname_len;
|
||||
k.qtype = sldns_wirerr_get_type(rr, rr_len, dname_len);
|
||||
k.qclass = sldns_wirerr_get_class(rr, rr_len, dname_len);
|
||||
k.local_alias = NULL;
|
||||
h = query_info_hash(&k, 0);
|
||||
|
||||
e = slabhash_lookup(runtime->daemon->env->msg_cache, h, &k, 0);
|
||||
if(e) {
|
||||
struct msgreply_entry* msg = (struct msgreply_entry*)e->key;
|
||||
struct reply_info* rep = (struct reply_info*)msg->entry.data;
|
||||
time_t expired = runtime->now_secs;
|
||||
expired -= 3;
|
||||
rep->ttl = expired;
|
||||
rep->prefetch_ttl = expired;
|
||||
rep->serve_expired_ttl = expired;
|
||||
lock_rw_unlock(&msg->entry.lock);
|
||||
}
|
||||
}
|
||||
|
||||
/** perform exponential backoff on the timeout */
|
||||
static void
|
||||
expon_timeout_backoff(struct replay_runtime* runtime)
|
||||
|
@ -796,6 +860,14 @@ do_moment_and_advance(struct replay_runtime* runtime)
|
|||
do_infra_rtt(runtime);
|
||||
advance_moment(runtime);
|
||||
break;
|
||||
case repevt_flush_message:
|
||||
do_flush_message(runtime);
|
||||
advance_moment(runtime);
|
||||
break;
|
||||
case repevt_expire_message:
|
||||
do_expire_message(runtime);
|
||||
advance_moment(runtime);
|
||||
break;
|
||||
default:
|
||||
fatal_exit("testbound: unknown event type %d",
|
||||
runtime->now->evt_type);
|
||||
|
|
|
@ -348,6 +348,20 @@ replay_moment_read(char* remain, FILE* in, const char* name,
|
|||
mom->string = strdup(m);
|
||||
if(!mom->string) fatal_exit("out of memory");
|
||||
if(!mom->variable) fatal_exit("out of memory");
|
||||
} else if(parse_keyword(&remain, "FLUSH_MESSAGE")) {
|
||||
mom->evt_type = repevt_flush_message;
|
||||
while(isspace((unsigned char)*remain))
|
||||
remain++;
|
||||
strip_end_white(remain);
|
||||
mom->string = strdup(remain);
|
||||
if(!mom->string) fatal_exit("out of memory");
|
||||
} else if(parse_keyword(&remain, "EXPIRE_MESSAGE")) {
|
||||
mom->evt_type = repevt_expire_message;
|
||||
while(isspace((unsigned char)*remain))
|
||||
remain++;
|
||||
strip_end_white(remain);
|
||||
mom->string = strdup(remain);
|
||||
if(!mom->string) fatal_exit("out of memory");
|
||||
} else {
|
||||
log_err("%d: unknown event type %s", pstate->lineno, remain);
|
||||
free(mom);
|
||||
|
|
|
@ -85,6 +85,8 @@
|
|||
* The file contents is macro expanded before match.
|
||||
* o CHECK_TEMPFILE [fname] - followed by FILE_BEGIN [to match] FILE_END
|
||||
* o INFRA_RTT [ip] [dp] [rtt] - update infra cache entry with rtt.
|
||||
* o FLUSH_MESSAGE name type class - flushes entry in message cache.
|
||||
* o EXPIRE_MESSAGE name type class - expires entry in message cache.
|
||||
* o ERROR
|
||||
* ; following entry starts on the next line, ENTRY_BEGIN.
|
||||
* ; more STEP items
|
||||
|
@ -148,6 +150,7 @@ struct fake_timer;
|
|||
struct replay_var;
|
||||
struct infra_cache;
|
||||
struct sldns_buffer;
|
||||
struct daemon;
|
||||
|
||||
/**
|
||||
* A replay scenario.
|
||||
|
@ -212,6 +215,10 @@ struct replay_moment {
|
|||
repevt_assign,
|
||||
/** store infra rtt cache entry: addr and string (int) */
|
||||
repevt_infra_rtt,
|
||||
/** flush message cache entry */
|
||||
repevt_flush_message,
|
||||
/** expire message cache entry */
|
||||
repevt_expire_message,
|
||||
/** cause traffic to flow */
|
||||
repevt_traffic
|
||||
}
|
||||
|
@ -297,6 +304,8 @@ struct replay_runtime {
|
|||
|
||||
/** ref the infra cache (was passed to outside_network_create) */
|
||||
struct infra_cache* infra;
|
||||
/** the daemon structure passed in worker call to remote accept open */
|
||||
struct daemon* daemon;
|
||||
|
||||
/** the current time in seconds */
|
||||
time_t now_secs;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "testcode/fake_event.h"
|
||||
#include "daemon/remote.h"
|
||||
#include "libunbound/worker.h"
|
||||
#include "daemon/worker.h"
|
||||
#include "util/config_file.h"
|
||||
#include "sldns/keyraw.h"
|
||||
#ifdef UB_ON_WINDOWS
|
||||
|
@ -532,9 +533,10 @@ void daemon_remote_clear(struct daemon_remote* ATTR_UNUSED(rc))
|
|||
}
|
||||
|
||||
int daemon_remote_open_accept(struct daemon_remote* ATTR_UNUSED(rc),
|
||||
struct listen_port* ATTR_UNUSED(ports),
|
||||
struct worker* ATTR_UNUSED(worker))
|
||||
struct listen_port* ATTR_UNUSED(ports), struct worker* worker)
|
||||
{
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)worker->base;
|
||||
runtime->daemon = worker->daemon;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -174,6 +174,7 @@ config_create(void)
|
|||
cfg->min_ttl = 0;
|
||||
cfg->max_ttl = 3600 * 24;
|
||||
cfg->max_negative_ttl = 3600;
|
||||
cfg->min_negative_ttl = 0;
|
||||
cfg->prefetch = 0;
|
||||
cfg->prefetch_key = 0;
|
||||
cfg->deny_any = 0;
|
||||
|
@ -308,6 +309,11 @@ config_create(void)
|
|||
cfg->minimal_responses = 1;
|
||||
cfg->rrset_roundrobin = 1;
|
||||
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 */
|
||||
if(!(cfg->server_key_file = strdup(RUN_DIR"/unbound_server.key")))
|
||||
goto error_exit;
|
||||
|
@ -384,6 +390,7 @@ config_create(void)
|
|||
if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit;
|
||||
if(!(cfg->cachedb_secret = strdup("default"))) goto error_exit;
|
||||
cfg->cachedb_no_store = 0;
|
||||
cfg->cachedb_check_when_serve_expired = 1;
|
||||
#ifdef USE_REDIS
|
||||
if(!(cfg->redis_server_host = strdup("127.0.0.1"))) goto error_exit;
|
||||
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;}
|
||||
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;}
|
||||
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)
|
||||
{ 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) {
|
||||
|
@ -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("rrset-roundrobin:", rrset_roundrobin)
|
||||
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_YNO("unblock-lan-zones:", unblock_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
|
||||
#ifdef USE_CACHEDB
|
||||
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 */
|
||||
else if(strcmp(opt, "define-tag:") ==0) {
|
||||
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_DEC(opt, "cache-max-ttl", max_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, "infra-host-ttl", host_ttl)
|
||||
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, "rrset-roundrobin", rrset_roundrobin)
|
||||
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
|
||||
else O_LST(opt, "send-client-subnet", client_subnet)
|
||||
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, "secret-seed", cachedb_secret)
|
||||
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
|
||||
else O_STR(opt, "redis-server-host", redis_server_host)
|
||||
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_datas);
|
||||
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_cert_file);
|
||||
free(cfg->control_key_file);
|
||||
|
@ -1761,6 +1783,10 @@ cfg_mark_ports(const char* str, int allow, int* avail, int num)
|
|||
#endif
|
||||
if(!mid) {
|
||||
int port = atoi(str);
|
||||
if(port < 0) {
|
||||
log_err("port number is negative: %d", port);
|
||||
return 0;
|
||||
}
|
||||
if(port == 0 && strcmp(str, "0") != 0) {
|
||||
log_err("cannot parse port number '%s'", str);
|
||||
return 0;
|
||||
|
@ -1770,6 +1796,10 @@ cfg_mark_ports(const char* str, int allow, int* avail, int num)
|
|||
} else {
|
||||
int i, low, high = atoi(mid+1);
|
||||
char buf[16];
|
||||
if(high < 0) {
|
||||
log_err("port number is negative: %d", high);
|
||||
return 0;
|
||||
}
|
||||
if(high == 0 && strcmp(mid+1, "0") != 0) {
|
||||
log_err("cannot parse port number '%s'", mid+1);
|
||||
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));
|
||||
buf[mid-str] = 0;
|
||||
low = atoi(buf);
|
||||
if(low < 0) {
|
||||
log_err("port number is negative: %d", low);
|
||||
return 0;
|
||||
}
|
||||
if(low == 0 && strcmp(buf, "0") != 0) {
|
||||
log_err("cannot parse port number '%s'", buf);
|
||||
return 0;
|
||||
}
|
||||
if(high > num) {
|
||||
/* Stop very high values from taking a long time. */
|
||||
high = num;
|
||||
}
|
||||
for(i=low; i<=high; i++) {
|
||||
if(i < num)
|
||||
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_ORIGINAL_TTL = config->serve_original_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_MAX_TIMEOUT = config->infra_cache_max_rtt;
|
||||
EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;
|
||||
|
|
|
@ -315,6 +315,8 @@ struct config_file {
|
|||
int min_ttl;
|
||||
/** the number of seconds maximal negative TTL for SOA in auth */
|
||||
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. */
|
||||
int prefetch;
|
||||
/** if prefetching of DNSKEYs should be performed. */
|
||||
|
@ -535,6 +537,21 @@ struct config_file {
|
|||
/* wait time for unknown server in msec */
|
||||
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 */
|
||||
size_t max_udp_size;
|
||||
|
||||
|
@ -705,6 +722,8 @@ struct config_file {
|
|||
char* cachedb_secret;
|
||||
/** cachedb that does not store, but only reads from database, if on */
|
||||
int cachedb_no_store;
|
||||
/** cachedb check before serving serve-expired response */
|
||||
int cachedb_check_when_serve_expired;
|
||||
#ifdef USE_REDIS
|
||||
/** redis server's IP address or host name */
|
||||
char* redis_server_host;
|
||||
|
|
|
@ -297,6 +297,7 @@ rrset-cache-size{COLON} { YDVAR(1, VAR_RRSET_CACHE_SIZE) }
|
|||
rrset-cache-slabs{COLON} { YDVAR(1, VAR_RRSET_CACHE_SLABS) }
|
||||
cache-max-ttl{COLON} { YDVAR(1, VAR_CACHE_MAX_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) }
|
||||
infra-host-ttl{COLON} { YDVAR(1, VAR_INFRA_HOST_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) }
|
||||
rrset-roundrobin{COLON} { YDVAR(1, VAR_RRSET_ROUNDROBIN) }
|
||||
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) }
|
||||
dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) }
|
||||
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) }
|
||||
secret-seed{COLON} { YDVAR(1, VAR_CACHEDB_SECRETSEED) }
|
||||
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-port{COLON} { YDVAR(1, VAR_CACHEDB_REDISPORT) }
|
||||
redis-server-path{COLON} { YDVAR(1, VAR_CACHEDB_REDISPATH) }
|
||||
|
|
|
@ -153,6 +153,7 @@ extern struct config_parser_state* cfg_parser;
|
|||
%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_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_DEFINE_TAG VAR_LOCAL_ZONE_TAG VAR_ACCESS_CONTROL_TAG
|
||||
%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_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_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_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6
|
||||
%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_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO
|
||||
%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 ;
|
||||
|
@ -298,6 +301,7 @@ content_server: server_num_threads | server_verbosity | server_port |
|
|||
server_min_client_subnet_ipv4 | server_min_client_subnet_ipv6 |
|
||||
server_max_ecs_tree_size_ipv4 | server_max_ecs_tree_size_ipv6 |
|
||||
server_caps_whitelist | server_cache_max_negative_ttl |
|
||||
server_cache_min_negative_ttl |
|
||||
server_permit_small_holddown | server_qname_minimisation |
|
||||
server_ip_freebind | server_define_tag | server_local_zone_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_tcp_connection_limit | server_log_servfail | server_deny_any |
|
||||
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_tls_ciphersuites | server_tls_session_ticket_keys |
|
||||
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);
|
||||
}
|
||||
;
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
;
|
||||
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
|
||||
{
|
||||
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 |
|
||||
redis_server_host | redis_server_port | redis_timeout |
|
||||
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
|
||||
{
|
||||
|
@ -3762,6 +3828,19 @@ cachedb_no_store: VAR_CACHEDB_NO_STORE STRING_ARG
|
|||
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
|
||||
{
|
||||
#if defined(USE_CACHEDB) && defined(USE_REDIS)
|
||||
|
|
|
@ -82,6 +82,8 @@ extern time_t MAX_TTL;
|
|||
extern time_t MIN_TTL;
|
||||
/** Maximum Negative TTL that is allowed */
|
||||
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 */
|
||||
extern int SERVE_EXPIRED;
|
||||
/** Time to serve records after expiration */
|
||||
|
|
|
@ -61,6 +61,8 @@ time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
|
|||
time_t MIN_TTL = 0;
|
||||
/** MAX Negative TTL, for SOA records in authority section */
|
||||
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 */
|
||||
int SERVE_EXPIRED = 0;
|
||||
/** 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) {
|
||||
/* negative response. see if TTL of SOA record larger than the
|
||||
* minimum-ttl in the rdata of the SOA record */
|
||||
if(*rr_ttl > soa_find_minttl(rr))
|
||||
*rr_ttl = soa_find_minttl(rr);
|
||||
}
|
||||
if(!SERVE_ORIGINAL_TTL && (*rr_ttl < MIN_TTL))
|
||||
*rr_ttl = MIN_TTL;
|
||||
if(!SERVE_ORIGINAL_TTL && (*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
|
||||
* else, it is for a more specific record */
|
||||
if(*rr_ttl > MAX_NEG_TTL)
|
||||
*rr_ttl = MAX_NEG_TTL;
|
||||
if(*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(MIN_NEG_TTL <= 0 && *rr_ttl < MIN_TTL) {
|
||||
*rr_ttl = MIN_TTL;
|
||||
}
|
||||
if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL;
|
||||
}
|
||||
/* MAX_NEG_TTL overrides the min and max ttl of everything
|
||||
* else; it is for a more specific record */
|
||||
if(*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)
|
||||
data->ttl = *rr_ttl;
|
||||
|
|
|
@ -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* p = buf;
|
||||
|
@ -148,7 +148,10 @@ char* errinf_to_str_bogus(struct module_qstate* qstate)
|
|||
snprintf(p, left, " %s", s->str);
|
||||
left -= strlen(p); p += strlen(p);
|
||||
}
|
||||
p = strdup(buf);
|
||||
if(region)
|
||||
p = regional_strdup(region, buf);
|
||||
else
|
||||
p = strdup(buf);
|
||||
if(!p)
|
||||
log_err("malloc failure in errinf_to_str");
|
||||
return p;
|
||||
|
@ -188,7 +191,7 @@ char* errinf_to_str_servfail(struct module_qstate* qstate)
|
|||
snprintf(p, left, " %s", s->str);
|
||||
left -= strlen(p); p += strlen(p);
|
||||
}
|
||||
p = strdup(buf);
|
||||
p = regional_strdup(qstate->region, buf);
|
||||
if(!p)
|
||||
log_err("malloc failure in errinf_to_str");
|
||||
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);
|
||||
left -= strlen(p); p += strlen(p);
|
||||
}
|
||||
p = strdup(buf);
|
||||
p = regional_strdup(qstate->region, buf);
|
||||
if(!p)
|
||||
log_err("malloc failure in errinf_to_str");
|
||||
return p;
|
||||
|
|
|
@ -180,6 +180,7 @@ struct iter_hints;
|
|||
struct respip_set;
|
||||
struct respip_client_info;
|
||||
struct respip_addr_info;
|
||||
struct module_stack;
|
||||
|
||||
/** Maximum number of modules in operation */
|
||||
#define MAX_MODULE 16
|
||||
|
@ -511,10 +512,10 @@ struct module_env {
|
|||
/** auth zones */
|
||||
struct auth_zones* auth_zones;
|
||||
/** Mapping of forwarding zones to targets.
|
||||
* iterator forwarder information. per-thread, created by worker */
|
||||
* iterator forwarder information. */
|
||||
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
|
||||
* expire. The hints are always used to "prime" the cache. Note
|
||||
* that both root hints and stub zone "hints" are stored in this
|
||||
|
@ -537,6 +538,12 @@ struct module_env {
|
|||
/** EDNS client string information */
|
||||
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. */
|
||||
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.
|
||||
* @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).
|
||||
* 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.
|
||||
|
@ -840,7 +848,6 @@ sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate);
|
|||
* Create error info in string. For other servfails.
|
||||
* @param qstate: query state.
|
||||
* @return string or NULL on malloc failure (already logged).
|
||||
* This string is malloced and has to be freed by caller.
|
||||
*/
|
||||
char* errinf_to_str_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.
|
||||
* @param qstate: query state.
|
||||
* @return string or NULL on malloc failure (already logged).
|
||||
* This string is malloced and has to be freed by caller.
|
||||
*/
|
||||
char* errinf_to_str_misc(struct module_qstate* qstate);
|
||||
|
||||
|
|
|
@ -77,6 +77,8 @@
|
|||
|
||||
/** max length of an IP address (the address portion) that we allow */
|
||||
#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 */
|
||||
uint16_t EDNS_ADVERTISED_SIZE = 4096;
|
||||
|
||||
|
@ -486,28 +488,38 @@ uint8_t* authextstrtodname(char* str, int* port, char** auth_name)
|
|||
*port = UNBOUND_DNS_PORT;
|
||||
*auth_name = NULL;
|
||||
if((s=strchr(str, '@'))) {
|
||||
char buf[MAX_HOST_STRLEN];
|
||||
size_t len = (size_t)(s-str);
|
||||
char* hash = strchr(s+1, '#');
|
||||
if(hash) {
|
||||
*auth_name = hash+1;
|
||||
} else {
|
||||
*auth_name = NULL;
|
||||
}
|
||||
if(len >= MAX_HOST_STRLEN) {
|
||||
return NULL;
|
||||
}
|
||||
(void)strlcpy(buf, str, sizeof(buf));
|
||||
buf[len] = 0;
|
||||
*port = atoi(s+1);
|
||||
if(*port == 0) {
|
||||
if(!hash && strcmp(s+1,"0")!=0)
|
||||
return 0;
|
||||
return NULL;
|
||||
if(hash && strncmp(s+1,"0#",2)!=0)
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
*s = 0;
|
||||
dname = sldns_str2wire_dname(str, &dname_len);
|
||||
*s = '@';
|
||||
dname = sldns_str2wire_dname(buf, &dname_len);
|
||||
} 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;
|
||||
*auth_name = s+1;
|
||||
*s = 0;
|
||||
dname = sldns_str2wire_dname(str, &dname_len);
|
||||
*s = '#';
|
||||
dname = sldns_str2wire_dname(buf, &dname_len);
|
||||
} else {
|
||||
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 {
|
||||
if(print_errno) {
|
||||
if(errno == 0)
|
||||
log_err("str: syscall error with errno %s",
|
||||
strerror(errno));
|
||||
else log_err("str: %s", strerror(errno));
|
||||
log_err("%s: syscall error with errno %s",
|
||||
str, strerror(errno));
|
||||
else log_err("%s: %s", str, strerror(errno));
|
||||
} else {
|
||||
log_err("str: %s", inf);
|
||||
log_err("%s: %s", str, inf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4772,9 +4772,9 @@ comm_point_send_reply(struct comm_reply *repinfo)
|
|||
* sending src (client)/dst (local service) addresses over DNSTAP from udp callback
|
||||
*/
|
||||
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);
|
||||
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
|
||||
} 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
|
||||
*/
|
||||
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);
|
||||
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 ));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -181,6 +181,8 @@ struct comm_point {
|
|||
/** if the event is added or not */
|
||||
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;
|
||||
|
||||
/** file descriptor for communication point */
|
||||
|
|
|
@ -89,7 +89,7 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
|
|||
# if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
|
||||
__BYTE_ORDER == __LITTLE_ENDIAN) || \
|
||||
(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_BIG_ENDIAN 0
|
||||
# elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
|
||||
|
|
|
@ -528,6 +528,40 @@ lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md)
|
|||
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
|
||||
lruhash_traverse(struct lruhash* h, int wr,
|
||||
void (*func)(struct lruhash_entry*, void*), void* arg)
|
||||
|
|
|
@ -303,6 +303,17 @@ void lru_touch(struct lruhash* table, struct lruhash_entry* entry);
|
|||
*/
|
||||
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 ************************/
|
||||
/*** these are used by getdns only and not by unbound. ***/
|
||||
|
||||
|
|
|
@ -166,6 +166,13 @@ int slabhash_is_size(struct slabhash* sl, size_t size, size_t slabs)
|
|||
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 i, total = sizeof(*sl);
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param table: hash table.
|
||||
|
|
|
@ -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)
|
||||
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
|
||||
* qtype=CNAME, this will yield a CNAME response. */
|
||||
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) {
|
||||
val_find_rrset_signer(rep->rrsets[i],
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -621,7 +621,6 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
* @param vq: validator query state.
|
||||
* @param env: module env for verify.
|
||||
* @param ve: validator env for verify.
|
||||
* @param qchase: query that was made.
|
||||
* @param chase_reply: answer to validate.
|
||||
* @param key_entry: the key entry, which is trusted, and which matches
|
||||
* 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
|
||||
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,
|
||||
int* suspend)
|
||||
{
|
||||
|
@ -640,7 +639,7 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
size_t i, slen;
|
||||
struct ub_packed_rrset_key* s;
|
||||
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;
|
||||
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
|
||||
*suspend = 0;
|
||||
|
@ -658,9 +657,13 @@ validate_msg_signatures(struct module_qstate* qstate, struct val_qstate* vq,
|
|||
/* Skip the CNAME following a (validated) DNAME.
|
||||
* Because of the normalization routines in the iterator,
|
||||
* there will always be an unsigned CNAME following a DNAME
|
||||
* (unless qtype=DNAME). */
|
||||
if(dname_seen && ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME) {
|
||||
dname_seen = 0;
|
||||
* (unless qtype=DNAME in the answer part). */
|
||||
if(i>0 && ntohs(chase_reply->rrsets[i-1]->rk.type) ==
|
||||
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 */
|
||||
/* since the DNAME verified, mark the CNAME as secure */
|
||||
((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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if(num_verifies > MAX_VALIDATE_AT_ONCE &&
|
||||
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;
|
||||
* 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)) {
|
||||
if(suspend) {
|
||||
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",
|
||||
&qstate->qinfo);
|
||||
else {
|
||||
char* err_str = errinf_to_str_bogus(qstate);
|
||||
char* err_str = errinf_to_str_bogus(qstate,
|
||||
qstate->region);
|
||||
if(err_str) {
|
||||
size_t err_str_len = strlen(err_str);
|
||||
log_info("%s", err_str);
|
||||
/* allocate space and store the error
|
||||
* 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);
|
||||
vq->orig_msg->rep->reason_bogus_str = err_str;
|
||||
}
|
||||
free(err_str);
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue