mirror of
https://github.com/fluencelabs/redis
synced 2025-06-16 02:31:20 +00:00
TLS: Connections refactoring and TLS support.
* Introduce a connection abstraction layer for all socket operations and integrate it across the code base. * Provide an optional TLS connections implementation based on OpenSSL. * Pull a newer version of hiredis with TLS support. * Tests, redis-cli updates for TLS support.
This commit is contained in:
@ -47,6 +47,9 @@
|
||||
#include <math.h>
|
||||
|
||||
#include <hiredis.h>
|
||||
#ifdef USE_OPENSSL
|
||||
#include <hiredis_ssl.h>
|
||||
#endif
|
||||
#include <sds.h> /* use sds.h from hiredis, so that only one set of sds functions will be present in the binary */
|
||||
#include "dict.h"
|
||||
#include "adlist.h"
|
||||
@ -188,6 +191,11 @@ static struct config {
|
||||
char *hostip;
|
||||
int hostport;
|
||||
char *hostsocket;
|
||||
int tls;
|
||||
char *sni;
|
||||
char *cacert;
|
||||
char *cert;
|
||||
char *key;
|
||||
long repeat;
|
||||
long interval;
|
||||
int dbnum;
|
||||
@ -751,6 +759,18 @@ static int cliSelect(void) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
/* Wrapper around redisSecureConnection to avoid hiredis_ssl dependencies if
|
||||
* not building with TLS support.
|
||||
*/
|
||||
static int cliSecureConnection(redisContext *c) {
|
||||
#ifdef USE_OPENSSL
|
||||
return redisSecureConnection(c, config.cacert, config.cert, config.key, config.sni);
|
||||
#else
|
||||
(void) c;
|
||||
return REDIS_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Connect to the server. It is possible to pass certain flags to the function:
|
||||
* CC_FORCE: The connection is performed even if there is already
|
||||
* a connected socket.
|
||||
@ -767,6 +787,16 @@ static int cliConnect(int flags) {
|
||||
context = redisConnectUnix(config.hostsocket);
|
||||
}
|
||||
|
||||
if (!context->err && config.tls) {
|
||||
if (cliSecureConnection(context) == REDIS_ERR && !context->err) {
|
||||
/* TODO: this check should be redundant, redis-cli should set err=1 */
|
||||
fprintf(stderr, "Could not negotiate a TLS connection.\n");
|
||||
context = NULL;
|
||||
redisFree(context);
|
||||
return REDIS_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->err) {
|
||||
if (!(flags & CC_QUIET)) {
|
||||
fprintf(stderr,"Could not connect to Redis at ");
|
||||
@ -782,6 +812,7 @@ static int cliConnect(int flags) {
|
||||
return REDIS_ERR;
|
||||
}
|
||||
|
||||
|
||||
/* Set aggressive KEEP_ALIVE socket option in the Redis context socket
|
||||
* in order to prevent timeouts caused by the execution of long
|
||||
* commands. At the same time this improves the detection of real
|
||||
@ -1245,6 +1276,9 @@ static redisReply *reconnectingRedisCommand(redisContext *c, const char *fmt, ..
|
||||
|
||||
redisFree(c);
|
||||
c = redisConnect(config.hostip,config.hostport);
|
||||
if (!c->err && config.tls) {
|
||||
cliSecureConnection(c);
|
||||
}
|
||||
usleep(1000000);
|
||||
}
|
||||
|
||||
@ -1434,6 +1468,18 @@ static int parseOptions(int argc, char **argv) {
|
||||
} else if (!strcmp(argv[i],"--cluster-search-multiple-owners")) {
|
||||
config.cluster_manager_command.flags |=
|
||||
CLUSTER_MANAGER_CMD_FLAG_CHECK_OWNERS;
|
||||
#ifdef USE_OPENSSL
|
||||
} else if (!strcmp(argv[i],"--tls")) {
|
||||
config.tls = 1;
|
||||
} else if (!strcmp(argv[i],"--sni")) {
|
||||
config.sni = argv[++i];
|
||||
} else if (!strcmp(argv[i],"--cacert")) {
|
||||
config.cacert = argv[++i];
|
||||
} else if (!strcmp(argv[i],"--cert")) {
|
||||
config.cert = argv[++i];
|
||||
} else if (!strcmp(argv[i],"--key")) {
|
||||
config.key = argv[++i];
|
||||
#endif
|
||||
} else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) {
|
||||
sds version = cliVersion();
|
||||
printf("redis-cli %s\n", version);
|
||||
@ -1522,6 +1568,12 @@ static void usage(void) {
|
||||
" -x Read last argument from STDIN.\n"
|
||||
" -d <delimiter> Multi-bulk delimiter in for raw formatting (default: \\n).\n"
|
||||
" -c Enable cluster mode (follow -ASK and -MOVED redirections).\n"
|
||||
#ifdef USE_OPENSSL
|
||||
" --tls Establish a secure TLS connection.\n"
|
||||
" --cacert CA Certificate file to verify with.\n"
|
||||
" --cert Client certificate to authenticate with.\n"
|
||||
" --key Private key file to authenticate with.\n"
|
||||
#endif
|
||||
" --raw Use raw formatting for replies (default when STDOUT is\n"
|
||||
" not a tty).\n"
|
||||
" --no-raw Force formatted output even when STDOUT is not a tty.\n"
|
||||
@ -1544,7 +1596,9 @@ static void usage(void) {
|
||||
" --pipe Transfer raw Redis protocol from stdin to server.\n"
|
||||
" --pipe-timeout <n> In --pipe mode, abort with error if after sending all data.\n"
|
||||
" no reply is received within <n> seconds.\n"
|
||||
" Default timeout: %d. Use 0 to wait forever.\n"
|
||||
" Default timeout: %d. Use 0 to wait forever.\n",
|
||||
version, REDIS_CLI_DEFAULT_PIPE_TIMEOUT);
|
||||
fprintf(stderr,
|
||||
" --bigkeys Sample Redis keys looking for keys with many elements (complexity).\n"
|
||||
" --memkeys Sample Redis keys looking for keys consuming a lot of memory.\n"
|
||||
" --memkeys-samples <n> Sample Redis keys looking for keys consuming a lot of memory.\n"
|
||||
@ -1567,8 +1621,7 @@ static void usage(void) {
|
||||
" line interface.\n"
|
||||
" --help Output this help and exit.\n"
|
||||
" --version Output version and exit.\n"
|
||||
"\n",
|
||||
version, REDIS_CLI_DEFAULT_PIPE_TIMEOUT);
|
||||
"\n");
|
||||
/* Using another fprintf call to avoid -Woverlength-strings compile warning */
|
||||
fprintf(stderr,
|
||||
"Cluster Manager Commands:\n"
|
||||
@ -2336,6 +2389,9 @@ cleanup:
|
||||
static int clusterManagerNodeConnect(clusterManagerNode *node) {
|
||||
if (node->context) redisFree(node->context);
|
||||
node->context = redisConnect(node->ip, node->port);
|
||||
if (!node->context->err && config.tls) {
|
||||
cliSecureConnection(node->context);
|
||||
}
|
||||
if (node->context->err) {
|
||||
fprintf(stderr,"Could not connect to Redis at ");
|
||||
fprintf(stderr,"%s:%d: %s\n", node->ip, node->port,
|
||||
|
Reference in New Issue
Block a user