#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"
return;
}
+ if(qstate->serve_expired_data &&
+ qstate->env->cfg->cachedb_check_when_serve_expired) {
+ /* 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;
{
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;
+}
#endif /* USE_CACHEDB */
*/
#include "util/module.h"
struct cachedb_backend;
+struct module_stack;
/**
* The global variable environment contents for the cachedb
*/
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);
#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;
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. */
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 &&
+ !(worker->env.cachedb_enabled &&
+ worker->env.cfg->cachedb_check_when_serve_expired)) {
if(worker->env.cfg->serve_expired_ttl &&
rep->serve_expired_ttl < timenow)
return 0;
+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.
+
9 April 2024: Yorgos
- Merge #1043 from xiaoxiaoafeifei: Add loongarch support; updates
config.guess(2024-01-01) and config.sub(2024-01-01), verified
# 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)
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 serve-expired is enabled, without serve-expired-client-timeout, 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.
+The default is yes.
.P
The following
.B cachedb
&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)
log_err("mesh_new_client: out of memory initializing serve expired");
goto servfail_mem;
}
+ 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;
+ }
+ }
/* update statistics */
if(was_detached) {
log_assert(mesh->num_detached_states > 0);
mesh_state_delete(&s->s);
return 0;
}
+ 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;
+ }
+ }
/* update statistics */
if(was_detached) {
log_assert(mesh->num_detached_states > 0);
}
}
+void
+mesh_respond_serve_expired(struct mesh_state* mstate)
+{
+ mesh_serve_expired_callback(mstate);
+}
+
int mesh_jostle_exceeded(struct mesh_area* mesh)
{
if(mesh->all.count < mesh->max_reply_states)
*/
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 */
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;
#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);
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)
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;
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) }
%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 ;
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
{
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)
/** EDNS client string information */
struct edns_strings* edns_strings;
+#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;
};