redis-logical-db configuration option.
const char* server_path; /* server's unix path, or "", NULL if unused */
const char* server_password; /* server's AUTH password, or "", NULL if unused */
struct timeval timeout; /* timeout for connection setup and commands */
+ int logical_db; /* the redis logical database to use */
};
static redisReply* redis_command(struct module_env*, struct cachedb_env*,
const char*, const uint8_t*, size_t);
+static void
+moddata_clean(struct redis_moddata** moddata) {
+ if(!moddata || !*moddata)
+ return;
+ if((*moddata)->ctxs) {
+ int i;
+ for(i = 0; i < (*moddata)->numctxs; i++) {
+ if((*moddata)->ctxs[i])
+ redisFree((*moddata)->ctxs[i]);
+ }
+ free((*moddata)->ctxs);
+ }
+ free(*moddata);
+ *moddata = NULL;
+}
+
static redisContext*
redis_connect(const struct redis_moddata* moddata)
{
}
freeReplyObject(rep);
}
+ if(moddata->logical_db > 0) {
+ redisReply* rep;
+ rep = redisCommand(ctx, "SELECT %d", moddata->logical_db);
+ if(!rep || rep->type == REDIS_REPLY_ERROR) {
+ log_err("failed to set logical database (%d)",
+ moddata->logical_db);
+ freeReplyObject(rep);
+ goto fail;
+ }
+ freeReplyObject(rep);
+ }
verbose(VERB_OPS, "Connection to Redis established");
return ctx;
- fail:
+fail:
if(ctx)
redisFree(ctx);
return NULL;
moddata = calloc(1, sizeof(struct redis_moddata));
if(!moddata) {
log_err("out of memory");
- return 0;
+ goto fail;
}
moddata->numctxs = env->cfg->num_threads;
moddata->ctxs = calloc(env->cfg->num_threads, sizeof(redisContext*));
if(!moddata->ctxs) {
log_err("out of memory");
- free(moddata);
- return 0;
+ goto fail;
}
/* note: server_host is a shallow reference to configured string.
* we don't have to free it in this module. */
moddata->server_password = env->cfg->redis_server_password;
moddata->timeout.tv_sec = env->cfg->redis_timeout / 1000;
moddata->timeout.tv_usec = (env->cfg->redis_timeout % 1000) * 1000;
- for(i = 0; i < moddata->numctxs; i++)
- moddata->ctxs[i] = redis_connect(moddata);
+ moddata->logical_db = env->cfg->redis_logical_db;
+ for(i = 0; i < moddata->numctxs; i++) {
+ redisContext* ctx = redis_connect(moddata);
+ if(!ctx) {
+ log_err("redis_init: failed to init redis");
+ goto fail;
+ }
+ moddata->ctxs[i] = ctx;
+ }
cachedb_env->backend_data = moddata;
if(env->cfg->redis_expire_records) {
redisReply* rep = NULL;
log_err("redis_init: failed to init redis, the "
"redis-expire-records option requires the SETEX command "
"(redis >= 2.0.0)");
- return 0;
+ goto fail;
}
redis_reply_type = rep->type;
freeReplyObject(rep);
log_err("redis_init: failed to init redis, the "
"redis-expire-records option requires the SETEX command "
"(redis >= 2.0.0)");
- return 0;
+ goto fail;
}
}
-
return 1;
+
+fail:
+ moddata_clean(&moddata);
+ return 0;
}
static void
(void)env;
verbose(VERB_OPS, "Redis deinitialization");
-
- if(!moddata)
- return;
- if(moddata->ctxs) {
- int i;
- for(i = 0; i < moddata->numctxs; i++) {
- if(moddata->ctxs[i])
- redisFree(moddata->ctxs[i]);
- }
- free(moddata->ctxs);
- }
- free(moddata);
+ moddata_clean(&moddata);
}
/*
+11 October 2023: George
+ - Fix #850: [FR] Ability to use specific database in Redis, with new
+ redis-logical-db configuration option.
+
10 October 2023: George
- Fix infinite loop when reading multiple lines of input on a broken
remote control socket. Addesses #947 and #948.
# redis-timeout: 100
# # set timeout on redis records based on DNS response TTL
# redis-expire-records: no
+# # redis logical database to use, 0 is the default database.
+# redis-logical-db: 0
# IPSet
# Add specify domain into set via ipset.
this option is internally reverted to "no". Redis SETEX support is required
for this option (Redis >= 2.0.0).
This option defaults to no.
+.TP
+.B redis-logical-db: \fI<logical database index>
+The logical database in Redis to use.
+These are databases in the same Redis instance sharing the same configuration
+and persisted in the same RDB/AOF file.
+If unsure about using this option, Redis documentation
+(https://redis.io/commands/select/) suggests not to use a single Redis instance
+for multiple unrelated applications.
+The default database in Redis is 0 while other logical databases need to be
+explicitly SELECT'ed upon connecting.
+This option defaults to 0.
.SS DNSTAP Logging Options
DNSTAP support, when compiled in by using \fB\-\-enable\-dnstap\fR, is enabled
in the \fBdnstap:\fR section.
cfg->redis_timeout = 100;
cfg->redis_server_port = 6379;
cfg->redis_expire_records = 0;
+ cfg->redis_logical_db = 0;
#endif /* USE_REDIS */
#endif /* USE_CACHEDB */
#ifdef USE_IPSET
else O_STR(opt, "redis-server-password", redis_server_password)
else O_DEC(opt, "redis-timeout", redis_timeout)
else O_YNO(opt, "redis-expire-records", redis_expire_records)
+ else O_DEC(opt, "redis-logical-db", redis_logical_db)
#endif /* USE_REDIS */
#endif /* USE_CACHEDB */
#ifdef USE_IPSET
int redis_timeout;
/** set timeout on redis records based on DNS response ttl */
int redis_expire_records;
+ /** set the redis logical database upon connection */
+ int redis_logical_db;
#endif
#endif
/** Downstream DNS Cookies */
redis-server-password{COLON} { YDVAR(1, VAR_CACHEDB_REDISPASSWORD) }
redis-timeout{COLON} { YDVAR(1, VAR_CACHEDB_REDISTIMEOUT) }
redis-expire-records{COLON} { YDVAR(1, VAR_CACHEDB_REDISEXPIRERECORDS) }
+redis-logical-db{COLON} { YDVAR(1, VAR_CACHEDB_REDISLOGICALDB) }
ipset{COLON} { YDVAR(0, VAR_IPSET) }
name-v4{COLON} { YDVAR(1, VAR_IPSET_NAME_V4) }
name-v6{COLON} { YDVAR(1, VAR_IPSET_NAME_V6) }
%token VAR_CACHEDB VAR_CACHEDB_BACKEND VAR_CACHEDB_SECRETSEED
%token VAR_CACHEDB_REDISHOST VAR_CACHEDB_REDISPORT VAR_CACHEDB_REDISTIMEOUT
%token VAR_CACHEDB_REDISEXPIRERECORDS VAR_CACHEDB_REDISPATH VAR_CACHEDB_REDISPASSWORD
+%token VAR_CACHEDB_REDISLOGICALDB
%token VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM VAR_FOR_UPSTREAM
%token VAR_AUTH_ZONE VAR_ZONEFILE VAR_MASTER VAR_URL VAR_FOR_DOWNSTREAM
%token VAR_FALLBACK_ENABLED VAR_TLS_ADDITIONAL_PORT VAR_LOW_RTT VAR_LOW_RTT_PERMIL
| ;
content_cachedb: cachedb_backend_name | cachedb_secret_seed |
redis_server_host | redis_server_port | redis_timeout |
- redis_expire_records | redis_server_path | redis_server_password
+ redis_expire_records | redis_server_path | redis_server_password |
+ redis_logical_db
;
cachedb_backend_name: VAR_CACHEDB_BACKEND STRING_ARG
{
free($2);
}
;
+redis_logical_db: VAR_CACHEDB_REDISLOGICALDB STRING_ARG
+ {
+ #if defined(USE_CACHEDB) && defined(USE_REDIS)
+ int db;
+ OUTYY(("P(redis_logical_db:%s)\n", $2));
+ db = atoi($2);
+ if((db == 0 && strcmp($2, "0") != 0) || db < 0)
+ yyerror("valid redis logical database index expected");
+ else cfg_parser->cfg->redis_logical_db = db;
+ #else
+ OUTYY(("P(Compiled without cachedb or redis, ignoring)\n"));
+ #endif
+ free($2);
+ }
+ ;
server_tcp_connection_limit: VAR_TCP_CONNECTION_LIMIT STRING_ARG STRING_ARG
{
OUTYY(("P(server_tcp_connection_limit:%s %s)\n", $2, $3));