summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOran Agra <oran@redislabs.com>2022-08-22 15:53:56 +0800
committerOran Agra <oran@redislabs.com>2022-08-23 12:37:56 +0300
commit4faddf18ca8ca3adb93cf1e4e620be9eaf0f6bf4 (patch)
treec2b70793b7052e4464d92849a21d308600ae7767 /src
parent89e11486880a59dad3857499e69e54c0b27be689 (diff)
downloadredis-4faddf18ca8ca3adb93cf1e4e620be9eaf0f6bf4.tar.gz
Build TLS as a loadable module
* Support BUILD_TLS=module to be loaded as a module via config file or command line. e.g. redis-server --loadmodule redis-tls.so * Updates to redismodule.h to allow it to be used side by side with server.h by defining REDISMODULE_CORE_MODULE * Changes to server.h, redismodule.h and module.c to avoid repeated type declarations (gcc 4.8 doesn't like these) * Add a mechanism for non-ABI neutral modules (ones who include server.h) to refuse loading if they detect not being built together with redis (release.c) * Fix wrong signature of RedisModuleDefragFunc, this could break compilation of a module, but not the ABI * Move initialization of listeners in server.c to be after loading the modules * Config TLS after initialization of listeners * Init cluster after initialization of listeners * Add TLS module to CI * Fix a test suite race conditions: Now that the listeners are initialized later, it's not sufficient to wait for the PID message in the log, we need to wait for the "Server Initialized" message. * Fix issues with moduleconfigs test as a result from start_server waiting for "Server Initialized" * Fix issues with modules/infra test as a result of an additional module present Notes about Sentinel: Sentinel can't really rely on the tls module, since it uses hiredis to initiate connections and depends on OpenSSL (won't be able to use any other connection modules for that), so it was decided that when TLS is built as a module, sentinel does not support TLS at all. This means that it keeps using redis_tls_ctx and redis_tls_client_ctx directly. Example code of config in redis-tls.so(may be use in the future): RedisModuleString *tls_cfg = NULL; void tlsInfo(RedisModuleInfoCtx *ctx, int for_crash_report) { UNUSED(for_crash_report); RedisModule_InfoAddSection(ctx, ""); RedisModule_InfoAddFieldLongLong(ctx, "var", 42); } int tlsCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) return RedisModule_WrongArity(ctx); return RedisModule_ReplyWithString(ctx, argv[1]); } RedisModuleString *getStringConfigCommand(const char *name, void *privdata) { REDISMODULE_NOT_USED(name); REDISMODULE_NOT_USED(privdata); return tls_cfg; } int setStringConfigCommand(const char *name, RedisModuleString *new, void *privdata, RedisModuleString **err) { REDISMODULE_NOT_USED(name); REDISMODULE_NOT_USED(err); REDISMODULE_NOT_USED(privdata); if (tls_cfg) RedisModule_FreeString(NULL, tls_cfg); RedisModule_RetainString(NULL, new); tls_cfg = new; return REDISMODULE_OK; } int RedisModule_OnLoad(void *ctx, RedisModuleString **argv, int argc) { .... if (RedisModule_CreateCommand(ctx,"tls",tlsCommand,"",0,0,0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_RegisterStringConfig(ctx, "cfg", "", REDISMODULE_CONFIG_DEFAULT, getStringConfigCommand, setStringConfigCommand, NULL, NULL) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_LoadConfigs(ctx) == REDISMODULE_ERR) { if (tls_cfg) { RedisModule_FreeString(ctx, tls_cfg); tls_cfg = NULL; } return REDISMODULE_ERR; } ... } Co-authored-by: zhenwei pi <pizhenwei@bytedance.com> Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile39
-rw-r--r--src/connection.h13
-rwxr-xr-xsrc/mkreleasehdr.sh2
-rw-r--r--src/module.c8
-rw-r--r--src/redismodule.h44
-rw-r--r--src/release.c7
-rw-r--r--src/sentinel.c16
-rw-r--r--src/server.c152
-rw-r--r--src/server.h25
-rw-r--r--src/tls.c62
10 files changed, 215 insertions, 153 deletions
diff --git a/src/Makefile b/src/Makefile
index 814f3c0aa..fdfef2b3c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -267,24 +267,41 @@ ifeq ($(MALLOC),jemalloc)
FINAL_LIBS := ../deps/jemalloc/lib/libjemalloc.a $(FINAL_LIBS)
endif
-ifeq ($(BUILD_TLS),yes)
- FINAL_CFLAGS+=-DUSE_OPENSSL $(OPENSSL_CFLAGS)
- FINAL_LDFLAGS+=$(OPENSSL_LDFLAGS)
- LIBSSL_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libssl && echo $$?)
+# LIBSSL & LIBCRYPTO
+LIBSSL_LIBS=
+LIBSSL_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libssl && echo $$?)
ifeq ($(LIBSSL_PKGCONFIG),0)
LIBSSL_LIBS=$(shell $(PKG_CONFIG) --libs libssl)
else
LIBSSL_LIBS=-lssl
endif
- LIBCRYPTO_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libcrypto && echo $$?)
+LIBCRYPTO_LIBS=
+LIBCRYPTO_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libcrypto && echo $$?)
ifeq ($(LIBCRYPTO_PKGCONFIG),0)
LIBCRYPTO_LIBS=$(shell $(PKG_CONFIG) --libs libcrypto)
else
LIBCRYPTO_LIBS=-lcrypto
endif
+
+BUILD_NO:=0
+BUILD_YES:=1
+BUILD_MODULE:=2
+ifeq ($(BUILD_TLS),yes)
+ FINAL_CFLAGS+=-DUSE_OPENSSL=$(BUILD_YES) $(OPENSSL_CFLAGS) -DBUILD_TLS_MODULE=$(BUILD_NO)
+ FINAL_LDFLAGS+=$(OPENSSL_LDFLAGS)
FINAL_LIBS += ../deps/hiredis/libhiredis_ssl.a $(LIBSSL_LIBS) $(LIBCRYPTO_LIBS)
endif
+TLS_MODULE=
+TLS_MODULE_NAME:=redis-tls$(PROG_SUFFIX).so
+TLS_MODULE_CFLAGS:=$(FINAL_CFLAGS)
+ifeq ($(BUILD_TLS),module)
+ FINAL_CFLAGS+=-DUSE_OPENSSL=$(BUILD_MODULE) $(OPENSSL_CFLAGS)
+ TLS_CLIENT_LIBS = ../deps/hiredis/libhiredis_ssl.a $(LIBSSL_LIBS) $(LIBCRYPTO_LIBS)
+ TLS_MODULE=$(TLS_MODULE_NAME)
+ TLS_MODULE_CFLAGS+=-DUSE_OPENSSL=$(BUILD_MODULE) $(OPENSSL_CFLAGS) -DBUILD_TLS_MODULE=$(BUILD_MODULE)
+endif
+
ifndef V
define MAKE_INSTALL
@printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$(1)$(ENDCOLOR) 1>&2
@@ -325,7 +342,7 @@ REDIS_CHECK_RDB_NAME=redis-check-rdb$(PROG_SUFFIX)
REDIS_CHECK_AOF_NAME=redis-check-aof$(PROG_SUFFIX)
ALL_SOURCES=$(sort $(patsubst %.o,%.c,$(REDIS_SERVER_OBJ) $(REDIS_CLI_OBJ) $(REDIS_BENCHMARK_OBJ)))
-all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME)
+all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) $(TLS_MODULE)
@echo ""
@echo "Hint: It's a good idea to run 'make test' ;)"
@echo ""
@@ -385,13 +402,17 @@ $(REDIS_CHECK_RDB_NAME): $(REDIS_SERVER_NAME)
$(REDIS_CHECK_AOF_NAME): $(REDIS_SERVER_NAME)
$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME)
+# redis-tls.so
+$(TLS_MODULE_NAME): $(REDIS_SERVER_NAME)
+ $(QUIET_CC)$(CC) -o $@ tls.c -shared -fPIC $(TLS_MODULE_CFLAGS) $(TLS_CLIENT_LIBS)
+
# redis-cli
$(REDIS_CLI_NAME): $(REDIS_CLI_OBJ)
- $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS)
+ $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(FINAL_LIBS) $(TLS_CLIENT_LIBS)
# redis-benchmark
$(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ)
- $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/libhdrhistogram.a $(FINAL_LIBS)
+ $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/libhdrhistogram.a $(FINAL_LIBS) $(TLS_CLIENT_LIBS)
DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ:%.o=%.d)
-include $(DEP)
@@ -410,7 +431,7 @@ commands.c: commands/*.json ../utils/generate-command-code.py
endif
clean:
- rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep
+ rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep *.so
rm -f $(DEP)
.PHONY: clean
diff --git a/src/connection.h b/src/connection.h
index 9fe5277e5..61ca205fe 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -107,8 +107,6 @@ typedef struct ConnectionType {
/* TLS specified methods */
sds (*get_peer_cert)(struct connection *conn);
- void* (*get_ctx)(void);
- void* (*get_client_ctx)(void);
} ConnectionType;
struct connection {
@@ -355,15 +353,6 @@ int connKeepAlive(connection *conn, int interval);
int connSendTimeout(connection *conn, long long ms);
int connRecvTimeout(connection *conn, long long ms);
-/* Helpers for tls special considerations */
-static inline void *connTypeGetCtx(ConnectionType *ct) {
- return ct->get_ctx();
-}
-
-static inline void *connTypeGetClientCtx(ConnectionType *ct) {
- return ct->get_client_ctx();
-}
-
/* Get cert for the secure connection */
static inline sds connGetPeerCert(connection *conn) {
if (conn->type->get_peer_cert) {
@@ -399,7 +388,7 @@ static inline connection *connCreate(ConnectionType *ct) {
return ct->conn_create();
}
-/* Create a accepted connection of specified type.
+/* Create an accepted connection of specified type.
* priv is connection type specified argument */
static inline connection *connCreateAccepted(ConnectionType *ct, int fd, void *priv) {
return ct->conn_create_accepted(fd, priv);
diff --git a/src/mkreleasehdr.sh b/src/mkreleasehdr.sh
index 236c26c2b..117b9e86f 100755
--- a/src/mkreleasehdr.sh
+++ b/src/mkreleasehdr.sh
@@ -11,4 +11,6 @@ test -f release.h || touch release.h
echo "#define REDIS_GIT_SHA1 \"$GIT_SHA1\"" > release.h
echo "#define REDIS_GIT_DIRTY \"$GIT_DIRTY\"" >> release.h
echo "#define REDIS_BUILD_ID \"$BUILD_ID\"" >> release.h
+echo "#include \"version.h\"" >> release.h
+echo "#define REDIS_BUILD_ID_RAW REDIS_VERSION REDIS_BUILD_ID REDIS_GIT_DIRTY REDIS_GIT_SHA1" >> release.h
touch release.c # Force recompile of release.c
diff --git a/src/module.c b/src/module.c
index 7644e2c77..f0f49837b 100644
--- a/src/module.c
+++ b/src/module.c
@@ -69,14 +69,14 @@
* pointers that have an API the module can call with them)
* -------------------------------------------------------------------------- */
-typedef struct RedisModuleInfoCtx {
+struct RedisModuleInfoCtx {
struct RedisModule *module;
dict *requested_sections;
sds info; /* info string we collected so far */
int sections; /* number of sections we collected so far */
int in_section; /* indication if we're in an active section or not */
int in_dict_field; /* indication that we're currently appending to a dict */
-} RedisModuleInfoCtx;
+};
/* This represents a shared API. Shared APIs will be used to populate
* the server.sharedapi dictionary, mapping names of APIs exported by
@@ -12211,13 +12211,13 @@ const char *RM_GetCurrentCommandName(RedisModuleCtx *ctx) {
/* The defrag context, used to manage state during calls to the data type
* defrag callback.
*/
-typedef struct RedisModuleDefragCtx {
+struct RedisModuleDefragCtx {
long defragged;
long long int endtime;
unsigned long *cursor;
struct redisObject *key; /* Optional name of key processed, NULL when unknown. */
int dbid; /* The dbid of the key being processed, -1 when unknown. */
-} RedisModuleDefragCtx;
+};
/* Register a defrag callback for global data, i.e. anything that the module
* may allocate that is not tied to a specific data type.
diff --git a/src/redismodule.h b/src/redismodule.h
index 6397e704e..36e8bf51f 100644
--- a/src/redismodule.h
+++ b/src/redismodule.h
@@ -750,13 +750,41 @@ typedef enum {
REDISMODULE_ACL_LOG_CHANNEL /* Channel authorization failure */
} RedisModuleACLLogEntryReason;
+/* Incomplete structures needed by both the core and modules. */
+typedef struct RedisModuleString RedisModuleString;
+typedef struct RedisModuleIO RedisModuleIO;
+typedef struct RedisModuleDigest RedisModuleDigest;
+typedef struct RedisModuleInfoCtx RedisModuleInfoCtx;
+typedef struct RedisModuleDefragCtx RedisModuleDefragCtx;
+
+/* Function pointers needed by both the core and modules, these needs to be
+ * exposed since you can't cast a function pointer to (void *). */
+typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report);
+typedef void (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx);
+typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata);
+
/* ------------------------- End of common defines ------------------------ */
-#ifndef REDISMODULE_CORE
+#if defined REDISMODULE_CORE
+/* Things only defined for the modules core (server), not exported to modules
+ * that include this file. */
+
+#define RedisModuleString robj
+
+#endif /* defined REDISMODULE_CORE */
+
+#if !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE
+/* Things defined for modules, but not for core-modules. */
typedef long long mstime_t;
typedef long long ustime_t;
+#endif /* !defined REDISMODULE_CORE && !defined REDISMODULE_CORE_MODULE */
+
+/* ----------- The rest of the defines are only for modules ----------------- */
+#if !defined REDISMODULE_CORE || defined REDISMODULE_CORE_MODULE
+/* Things defined for modules and core-modules. */
+
/* Macro definitions specific to individual compilers */
#ifndef REDISMODULE_ATTR_UNUSED
# ifdef __GNUC__
@@ -786,21 +814,16 @@ typedef long long ustime_t;
typedef struct RedisModuleCtx RedisModuleCtx;
typedef struct RedisModuleCommand RedisModuleCommand;
typedef struct RedisModuleKey RedisModuleKey;
-typedef struct RedisModuleString RedisModuleString;
typedef struct RedisModuleCallReply RedisModuleCallReply;
-typedef struct RedisModuleIO RedisModuleIO;
typedef struct RedisModuleType RedisModuleType;
-typedef struct RedisModuleDigest RedisModuleDigest;
typedef struct RedisModuleBlockedClient RedisModuleBlockedClient;
typedef struct RedisModuleClusterInfo RedisModuleClusterInfo;
typedef struct RedisModuleDict RedisModuleDict;
typedef struct RedisModuleDictIter RedisModuleDictIter;
typedef struct RedisModuleCommandFilterCtx RedisModuleCommandFilterCtx;
typedef struct RedisModuleCommandFilter RedisModuleCommandFilter;
-typedef struct RedisModuleInfoCtx RedisModuleInfoCtx;
typedef struct RedisModuleServerInfoData RedisModuleServerInfoData;
typedef struct RedisModuleScanCursor RedisModuleScanCursor;
-typedef struct RedisModuleDefragCtx RedisModuleDefragCtx;
typedef struct RedisModuleUser RedisModuleUser;
typedef struct RedisModuleKeyOptCtx RedisModuleKeyOptCtx;
@@ -827,11 +850,8 @@ typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const cha
typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data);
typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter);
typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data);
-typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report);
typedef void (*RedisModuleScanCB)(RedisModuleCtx *ctx, RedisModuleString *keyname, RedisModuleKey *key, void *privdata);
typedef void (*RedisModuleScanKeyCB)(RedisModuleKey *key, RedisModuleString *field, RedisModuleString *value, void *privdata);
-typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata);
-typedef int (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx);
typedef RedisModuleString * (*RedisModuleConfigGetStringFunc)(const char *name, void *privdata);
typedef long long (*RedisModuleConfigGetNumericFunc)(const char *name, void *privdata);
typedef int (*RedisModuleConfigGetBoolFunc)(const char *name, void *privdata);
@@ -1559,11 +1579,5 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
#define RMAPI_FUNC_SUPPORTED(func) (func != NULL)
-#else
-
-/* Things only defined for the modules core, not exported to modules
- * including this file. */
-#define RedisModuleString robj
-
#endif /* REDISMODULE_CORE */
#endif /* REDISMODULE_H */
diff --git a/src/release.c b/src/release.c
index e0bd018fc..adc7e55dd 100644
--- a/src/release.c
+++ b/src/release.c
@@ -35,7 +35,6 @@
#include <stdio.h>
#include "release.h"
-#include "version.h"
#include "crc64.h"
char *redisGitSHA1(void) {
@@ -46,8 +45,12 @@ char *redisGitDirty(void) {
return REDIS_GIT_DIRTY;
}
+const char *redisBuildIdRaw(void) {
+ return REDIS_BUILD_ID_RAW;
+}
+
uint64_t redisBuildId(void) {
- char *buildid = REDIS_VERSION REDIS_BUILD_ID REDIS_GIT_DIRTY REDIS_GIT_SHA1;
+ char *buildid = REDIS_BUILD_ID_RAW;
return crc64(0,(unsigned char*)buildid,strlen(buildid));
}
diff --git a/src/sentinel.c b/src/sentinel.c
index 881f4b909..a75eb3236 100644
--- a/src/sentinel.c
+++ b/src/sentinel.c
@@ -30,7 +30,7 @@
#include "server.h"
#include "hiredis.h"
-#ifdef USE_OPENSSL
+#if USE_OPENSSL == 1 /* BUILD_YES */
#include "openssl/ssl.h"
#include "hiredis_ssl.h"
#endif
@@ -44,6 +44,11 @@
extern char **environ;
+#if USE_OPENSSL == 1 /* BUILD_YES */
+extern SSL_CTX *redis_tls_ctx;
+extern SSL_CTX *redis_tls_client_ctx;
+#endif
+
#define REDIS_SENTINEL_PORT 26379
/* ======================== Sentinel global state =========================== */
@@ -2373,12 +2378,7 @@ void sentinelSetClientName(sentinelRedisInstance *ri, redisAsyncContext *c, char
}
static int instanceLinkNegotiateTLS(redisAsyncContext *context) {
-#ifndef USE_OPENSSL
- (void) context;
-#else
- SSL_CTX *redis_tls_ctx = connTypeGetCtx(connectionTypeTls());
- SSL_CTX *redis_tls_client_ctx = connTypeGetClientCtx(connectionTypeTls());
-
+#if USE_OPENSSL == 1 /* BUILD_YES */
if (!redis_tls_ctx) return C_ERR;
SSL *ssl = SSL_new(redis_tls_client_ctx ? redis_tls_client_ctx : redis_tls_ctx);
if (!ssl) return C_ERR;
@@ -2387,6 +2387,8 @@ static int instanceLinkNegotiateTLS(redisAsyncContext *context) {
SSL_free(ssl);
return C_ERR;
}
+#else
+ UNUSED(context);
#endif
return C_OK;
}
diff --git a/src/server.c b/src/server.c
index f01805840..b6a72ae88 100644
--- a/src/server.c
+++ b/src/server.c
@@ -2446,12 +2446,6 @@ void initServer(void) {
exit(1);
}
- if ((server.tls_port || server.tls_replication || server.tls_cluster)
- && connTypeConfigure(connectionTypeTls(), &server.tls_ctx_config, 1) == C_ERR) {
- serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
- exit(1);
- }
-
for (j = 0; j < CLIENT_MEM_USAGE_BUCKETS; j++) {
server.client_mem_usage_buckets[j].mem_usage_sum = 0;
server.client_mem_usage_buckets[j].clients = listCreate();
@@ -2470,40 +2464,6 @@ void initServer(void) {
}
server.db = zmalloc(sizeof(redisDb)*server.dbnum);
- /* Setup listeners from server config for TCP/TLS/Unix */
- int conn_index;
- connListener *listener;
- if (server.port != 0) {
- conn_index = connectionIndexByType(CONN_TYPE_SOCKET);
- if (conn_index < 0)
- serverPanic("Failed finding connection listener of %s", CONN_TYPE_SOCKET);
- listener = &server.listeners[conn_index];
- listener->bindaddr = server.bindaddr;
- listener->bindaddr_count = server.bindaddr_count;
- listener->port = server.port;
- listener->ct = connectionByType(CONN_TYPE_SOCKET);
- }
- if (server.tls_port != 0) {
- conn_index = connectionIndexByType(CONN_TYPE_TLS);
- if (conn_index < 0)
- serverPanic("Failed finding connection listener of %s", CONN_TYPE_TLS);
- listener = &server.listeners[conn_index];
- listener->bindaddr = server.bindaddr;
- listener->bindaddr_count = server.bindaddr_count;
- listener->port = server.tls_port;
- listener->ct = connectionByType(CONN_TYPE_TLS);
- }
- if (server.unixsocket != NULL) {
- conn_index = connectionIndexByType(CONN_TYPE_UNIX);
- if (conn_index < 0)
- serverPanic("Failed finding connection listener of %s", CONN_TYPE_UNIX);
- listener = &server.listeners[conn_index];
- listener->bindaddr = &server.unixsocket;
- listener->bindaddr_count = 1;
- listener->ct = connectionByType(CONN_TYPE_UNIX);
- listener->priv = &server.unixsocketperm; /* Unix socket specified */
- }
-
/* Create the Redis databases, and initialize other internal state. */
for (j = 0; j < server.dbnum; j++) {
server.db[j].dict = dictCreate(&dbDictType);
@@ -2584,29 +2544,6 @@ void initServer(void) {
exit(1);
}
- /* create all the configured listener, and add handler to start to accept */
- int listen_fds = 0;
- for (j = 0; j < CONN_TYPE_MAX; j++) {
- listener = &server.listeners[j];
- if (listener->ct == NULL)
- continue;
-
- if (connListen(listener) == C_ERR) {
- serverLog(LL_WARNING, "Failed listening on port %u (%s), aborting.", listener->port, listener->ct->get_type(NULL));
- exit(1);
- }
-
- if (createSocketAcceptHandler(listener, connAcceptHandler(listener->ct)) != C_OK)
- serverPanic("Unrecoverable error creating %s listener accept handler.", listener->ct->get_type(NULL));
-
- listen_fds += listener->count;
- }
-
- if (listen_fds == 0) {
- serverLog(LL_WARNING, "Configured to not listen anywhere, exiting.");
- exit(1);
- }
-
/* Register a readable event for the pipe used to awake the event loop
* from module threads. */
if (aeCreateFileEvent(server.el, server.module_pipe[0], AE_READABLE,
@@ -2630,7 +2567,6 @@ void initServer(void) {
server.maxmemory_policy = MAXMEMORY_NO_EVICTION;
}
- if (server.cluster_enabled) clusterInit();
scriptingInit(1);
functionsInit();
slowlogInit();
@@ -2642,6 +2578,78 @@ void initServer(void) {
applyWatchdogPeriod();
}
+void initListeners() {
+ /* Setup listeners from server config for TCP/TLS/Unix */
+ int conn_index;
+ connListener *listener;
+ if (server.port != 0) {
+ conn_index = connectionIndexByType(CONN_TYPE_SOCKET);
+ if (conn_index < 0)
+ serverPanic("Failed finding connection listener of %s", CONN_TYPE_SOCKET);
+ listener = &server.listeners[conn_index];
+ listener->bindaddr = server.bindaddr;
+ listener->bindaddr_count = server.bindaddr_count;
+ listener->port = server.port;
+ listener->ct = connectionByType(CONN_TYPE_SOCKET);
+ }
+
+ if (server.tls_port || server.tls_replication || server.tls_cluster) {
+ ConnectionType *ct_tls = connectionTypeTls();
+ if (!ct_tls) {
+ serverLog(LL_WARNING, "Failed finding TLS support.");
+ exit(1);
+ }
+ if (connTypeConfigure(ct_tls, &server.tls_ctx_config, 1) == C_ERR) {
+ serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
+ exit(1);
+ }
+ }
+
+ if (server.tls_port != 0) {
+ conn_index = connectionIndexByType(CONN_TYPE_TLS);
+ if (conn_index < 0)
+ serverPanic("Failed finding connection listener of %s", CONN_TYPE_TLS);
+ listener = &server.listeners[conn_index];
+ listener->bindaddr = server.bindaddr;
+ listener->bindaddr_count = server.bindaddr_count;
+ listener->port = server.tls_port;
+ listener->ct = connectionByType(CONN_TYPE_TLS);
+ }
+ if (server.unixsocket != NULL) {
+ conn_index = connectionIndexByType(CONN_TYPE_UNIX);
+ if (conn_index < 0)
+ serverPanic("Failed finding connection listener of %s", CONN_TYPE_UNIX);
+ listener = &server.listeners[conn_index];
+ listener->bindaddr = &server.unixsocket;
+ listener->bindaddr_count = 1;
+ listener->ct = connectionByType(CONN_TYPE_UNIX);
+ listener->priv = &server.unixsocketperm; /* Unix socket specified */
+ }
+
+ /* create all the configured listener, and add handler to start to accept */
+ int listen_fds = 0;
+ for (int j = 0; j < CONN_TYPE_MAX; j++) {
+ listener = &server.listeners[j];
+ if (listener->ct == NULL)
+ continue;
+
+ if (connListen(listener) == C_ERR) {
+ serverLog(LL_WARNING, "Failed listening on port %u (%s), aborting.", listener->port, listener->ct->get_type(NULL));
+ exit(1);
+ }
+
+ if (createSocketAcceptHandler(listener, connAcceptHandler(listener->ct)) != C_OK)
+ serverPanic("Unrecoverable error creating %s listener accept handler.", listener->ct->get_type(NULL));
+
+ listen_fds += listener->count;
+ }
+
+ if (listen_fds == 0) {
+ serverLog(LL_WARNING, "Configured to not listen anywhere, exiting.");
+ exit(1);
+ }
+}
+
/* Some steps in server initialization need to be done last (after modules
* are loaded).
* Specifically, creation of threads due to a race bug in ld.so, in which
@@ -7086,6 +7094,16 @@ int main(int argc, char **argv) {
if (server.set_proc_title) redisSetProcTitle(NULL);
redisAsciiArt();
checkTcpBacklogSettings();
+ if (!server.sentinel_mode) {
+ moduleInitModulesSystemLast();
+ moduleLoadFromQueue();
+ }
+ ACLLoadUsersAtStartup();
+ initListeners();
+ if (server.cluster_enabled) {
+ clusterInit();
+ }
+ InitServerLast();
if (!server.sentinel_mode) {
/* Things not needed when running in Sentinel mode. */
@@ -7114,10 +7132,6 @@ int main(int argc, char **argv) {
}
#endif /* __arm64__ */
#endif /* __linux__ */
- moduleInitModulesSystemLast();
- moduleLoadFromQueue();
- ACLLoadUsersAtStartup();
- InitServerLast();
aofLoadManifestFromDisk();
loadDataFromDisk();
aofOpenIfNeededOnServerStart();
@@ -7148,8 +7162,6 @@ int main(int argc, char **argv) {
redisCommunicateSystemd("READY=1\n");
}
} else {
- ACLLoadUsersAtStartup();
- InitServerLast();
sentinelIsRunning();
if (server.supervised_mode == SUPERVISED_SYSTEMD) {
redisCommunicateSystemd("STATUS=Ready to accept connections\n");
diff --git a/src/server.h b/src/server.h
index 65faa84af..8a0a2f5f6 100644
--- a/src/server.h
+++ b/src/server.h
@@ -81,6 +81,7 @@ typedef long long ustime_t; /* microsecond time type. */
#include "connection.h" /* Connection abstraction */
#define REDISMODULE_CORE 1
+typedef struct redisObject robj;
#include "redismodule.h" /* Redis modules API defines. */
/* Following includes allow test functions to be called from Redis main() */
@@ -679,9 +680,6 @@ struct RedisModuleIO;
struct RedisModuleDigest;
struct RedisModuleCtx;
struct moduleLoadQueueEntry;
-struct redisObject;
-struct RedisModuleDefragCtx;
-struct RedisModuleInfoCtx;
struct RedisModuleKeyOptCtx;
struct RedisModuleCommand;
@@ -701,20 +699,12 @@ typedef size_t (*moduleTypeFreeEffortFunc)(struct redisObject *key, const void *
typedef void (*moduleTypeUnlinkFunc)(struct redisObject *key, void *value);
typedef void *(*moduleTypeCopyFunc)(struct redisObject *fromkey, struct redisObject *tokey, const void *value);
typedef int (*moduleTypeDefragFunc)(struct RedisModuleDefragCtx *ctx, struct redisObject *key, void **value);
-typedef void (*RedisModuleInfoFunc)(struct RedisModuleInfoCtx *ctx, int for_crash_report);
-typedef void (*RedisModuleDefragFunc)(struct RedisModuleDefragCtx *ctx);
typedef size_t (*moduleTypeMemUsageFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size);
typedef void (*moduleTypeFreeFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value);
typedef size_t (*moduleTypeFreeEffortFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value);
typedef void (*moduleTypeUnlinkFunc2)(struct RedisModuleKeyOptCtx *ctx, void *value);
typedef void *(*moduleTypeCopyFunc2)(struct RedisModuleKeyOptCtx *ctx, const void *value);
-/* This callback type is called by moduleNotifyUserChanged() every time
- * a user authenticated via the module API is associated with a different
- * user or gets disconnected. This needs to be exposed since you can't cast
- * a function pointer to (void *). */
-typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata);
-
/* The module type, which is referenced in each value of a given type, defines
* the methods and links to the module exporting the type. */
@@ -786,7 +776,7 @@ typedef struct RedisModule RedisModule;
/* This is a wrapper for the 'rio' streams used inside rdb.c in Redis, so that
* the user does not have to take the total count of the written bytes nor
* to care about error conditions. */
-typedef struct RedisModuleIO {
+struct RedisModuleIO {
size_t bytes; /* Bytes read / written so far. */
rio *rio; /* Rio stream. */
moduleType *type; /* Module type doing the operation. */
@@ -794,7 +784,7 @@ typedef struct RedisModuleIO {
struct RedisModuleCtx *ctx; /* Optional context, see RM_GetContextFromIO()*/
struct redisObject *key; /* Optional name of key processed */
int dbid; /* The dbid of the key being processed, -1 when unknown. */
-} RedisModuleIO;
+};
/* Macro to initialize an IO context. Note that the 'ver' field is populated
* inside rdb.c according to the version of the value to load. */
@@ -813,12 +803,12 @@ typedef struct RedisModuleIO {
* a data structure, so that a digest can be created in a way that correctly
* reflects the values. See the DEBUG DIGEST command implementation for more
* background. */
-typedef struct RedisModuleDigest {
+struct RedisModuleDigest {
unsigned char o[20]; /* Ordered elements. */
unsigned char x[20]; /* Xored elements. */
struct redisObject *key; /* Optional name of key processed */
int dbid; /* The dbid of the key being processed */
-} RedisModuleDigest;
+};
/* Just start with a digest composed of all zero bytes. */
#define moduleInitDigestContext(mdvar) do { \
@@ -849,7 +839,7 @@ typedef struct RedisModuleDigest {
#define OBJ_SHARED_REFCOUNT INT_MAX /* Global object never destroyed. */
#define OBJ_STATIC_REFCOUNT (INT_MAX-1) /* Object allocated in the stack. */
#define OBJ_FIRST_SPECIAL_REFCOUNT OBJ_STATIC_REFCOUNT
-typedef struct redisObject {
+struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
@@ -857,7 +847,7 @@ typedef struct redisObject {
* and most significant 16 bits access time). */
int refcount;
void *ptr;
-} robj;
+};
/* The a string name for an object's type as listed above
* Native types are checked against the OBJ_STRING, OBJ_LIST, OBJ_* defines,
@@ -3269,6 +3259,7 @@ void *dictSdsDup(dict *d, const void *key);
char *redisGitSHA1(void);
char *redisGitDirty(void);
uint64_t redisBuildId(void);
+const char *redisBuildIdRaw(void);
char *redisBuildIdString(void);
/* Commands prototypes */
diff --git a/src/tls.c b/src/tls.c
index be6bf4e1b..99cbea5a2 100644
--- a/src/tls.c
+++ b/src/tls.c
@@ -27,12 +27,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define REDISMODULE_CORE_MODULE /* A module that's part of the redis core, uses server.h too. */
#include "server.h"
#include "connhelpers.h"
#include "adlist.h"
-#ifdef USE_OPENSSL
+#if (USE_OPENSSL == 1 /* BUILD_YES */ ) || ((USE_OPENSSL == 2 /* BUILD_MODULE */) && (BUILD_TLS_MODULE == 2))
#include <openssl/conf.h>
#include <openssl/ssl.h>
@@ -56,8 +57,8 @@
#define REDIS_TLS_PROTO_DEFAULT (REDIS_TLS_PROTO_TLSv1_2)
#endif
-static SSL_CTX *redis_tls_ctx = NULL;
-static SSL_CTX *redis_tls_client_ctx = NULL;
+SSL_CTX *redis_tls_ctx = NULL;
+SSL_CTX *redis_tls_client_ctx = NULL;
static int parseProtocolsConfig(const char *str) {
int i, count = 0;
@@ -1087,14 +1088,6 @@ static sds connTLSGetPeerCert(connection *conn_) {
return cert_pem;
}
-static void *tlsGetCtx(void) {
- return redis_tls_ctx;
-}
-
-static void *tlsGetClientCtx(void) {
- return redis_tls_client_ctx;
-}
-
static ConnectionType CT_TLS = {
/* connection type */
.get_type = connTLSGetType,
@@ -1137,20 +1130,55 @@ static ConnectionType CT_TLS = {
/* TLS specified methods */
.get_peer_cert = connTLSGetPeerCert,
- .get_ctx = tlsGetCtx,
- .get_client_ctx = tlsGetClientCtx
};
-int RedisRegisterConnectionTypeTLS()
-{
+int RedisRegisterConnectionTypeTLS() {
return connTypeRegister(&CT_TLS);
}
#else /* USE_OPENSSL */
-int RedisRegisterConnectionTypeTLS()
-{
+int RedisRegisterConnectionTypeTLS() {
+ serverLog(LL_VERBOSE, "Connection type %s not builtin", CONN_TYPE_TLS);
return C_ERR;
}
#endif
+
+#if BUILD_TLS_MODULE == 2 /* BUILD_MODULE */
+
+#include "release.h"
+
+int RedisModule_OnLoad(void *ctx, RedisModuleString **argv, int argc) {
+ UNUSED(argv);
+ UNUSED(argc);
+
+ /* Connection modules must be part of the same build as redis. */
+ if (strcmp(REDIS_BUILD_ID_RAW, redisBuildIdRaw())) {
+ serverLog(LL_NOTICE, "Connection type %s was not built together with the redis-server used.", CONN_TYPE_TLS);
+ return REDISMODULE_ERR;
+ }
+
+ if (RedisModule_Init(ctx,"tls",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR)
+ return REDISMODULE_ERR;
+
+ /* Connection modules is available only bootup. */
+ if ((RedisModule_GetContextFlags(ctx) & REDISMODULE_CTX_FLAGS_SERVER_STARTUP) == 0) {
+ serverLog(LL_NOTICE, "Connection type %s can be loaded only during bootup", CONN_TYPE_TLS);
+ return REDISMODULE_ERR;
+ }
+
+ RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD);
+
+ if(connTypeRegister(&CT_TLS) != C_OK)
+ return REDISMODULE_ERR;
+
+ return REDISMODULE_OK;
+}
+
+int RedisModule_OnUnload(void *arg) {
+ UNUSED(arg);
+ serverLog(LL_NOTICE, "Connection type %s can not be unloaded", CONN_TYPE_TLS);
+ return REDISMODULE_ERR;
+}
+#endif