Introduce connection layer framework
Use connTypeRegister() to register a connection type into redis, and query connection by connectionByType() via type. With this change, we can hide TLS specified methods into connection type: - void tlsInit(void); - void tlsCleanup(void); - int tlsConfigure(redisTLSContextConfig *ctx_config); - int isTlsConfigured(void); Merge isTlsConfigured & tlsConfigure, use an argument *reconfigure* to distinguish: tlsConfigure(&server.tls_ctx_config) -> onnTypeConfigure(CONN_TYPE_TLS, &server.tls_ctx_config, 1) isTlsConfigured() && tlsConfigure(&server.tls_ctx_config) -> connTypeConfigure(CONN_TYPE_TLS, &server.tls_ctx_config, 0) Finally, we can remove USE_OPENSSL from config.c. If redis is built without TLS, and still run redis with TLS, then redis reports: # Missing implement of connection type 1 # Failed to configure TLS. Check logs for more info. The log can be optimised, let's leave it in the future. Maybe we can use connection type as a string. Although uninitialized fields of a static struct are zero, we still set them as NULL explicitly in socket.c, let them clear to read & maintain: .init = NULL, .cleanup = NULL, .configure = NULL, Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
This commit is contained in:
parent
bff7ecc786
commit
8234a5123d
@ -316,7 +316,7 @@ endif
|
||||
|
||||
REDIS_SERVER_NAME=redis-server$(PROG_SUFFIX)
|
||||
REDIS_SENTINEL_NAME=redis-sentinel$(PROG_SUFFIX)
|
||||
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o eval.o bio.o rio.o rand.o memtest.o syscheck.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o tracking.o socket.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o script_lua.o script.o functions.o function_lua.o commands.o strl.o
|
||||
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o eval.o bio.o rio.o rand.o memtest.o syscheck.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o tracking.o socket.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o script_lua.o script.o functions.o function_lua.o commands.o strl.o connection.o
|
||||
REDIS_CLI_NAME=redis-cli$(PROG_SUFFIX)
|
||||
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o ae.o redisassert.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o strl.o
|
||||
REDIS_BENCHMARK_NAME=redis-benchmark$(PROG_SUFFIX)
|
||||
|
10
src/config.c
10
src/config.c
@ -30,6 +30,7 @@
|
||||
|
||||
#include "server.h"
|
||||
#include "cluster.h"
|
||||
#include "connection.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
@ -2571,13 +2572,12 @@ int updateClusterHostname(const char **err) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
static int applyTlsCfg(const char **err) {
|
||||
UNUSED(err);
|
||||
|
||||
/* If TLS is enabled, try to configure OpenSSL. */
|
||||
if ((server.tls_port || server.tls_replication || server.tls_cluster)
|
||||
&& tlsConfigure(&server.tls_ctx_config) == C_ERR) {
|
||||
&& connTypeConfigure(CONN_TYPE_TLS, &server.tls_ctx_config, 1) == C_ERR) {
|
||||
*err = "Unable to update TLS configuration. Check server logs.";
|
||||
return 0;
|
||||
}
|
||||
@ -2586,7 +2586,7 @@ static int applyTlsCfg(const char **err) {
|
||||
|
||||
static int applyTLSPort(const char **err) {
|
||||
/* Configure TLS in case it wasn't enabled */
|
||||
if (!isTlsConfigured() && tlsConfigure(&server.tls_ctx_config) == C_ERR) {
|
||||
if (connTypeConfigure(CONN_TYPE_TLS, &server.tls_ctx_config, 0) == C_ERR) {
|
||||
*err = "Unable to update TLS configuration. Check server logs.";
|
||||
return 0;
|
||||
}
|
||||
@ -2599,8 +2599,6 @@ static int applyTLSPort(const char **err) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* USE_OPENSSL */
|
||||
|
||||
static int setConfigDirOption(standardConfig *config, sds *argv, int argc, const char **err) {
|
||||
UNUSED(config);
|
||||
if (argc != 1) {
|
||||
@ -3109,7 +3107,6 @@ standardConfig static_configs[] = {
|
||||
createOffTConfig("auto-aof-rewrite-min-size", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, server.aof_rewrite_min_size, 64*1024*1024, MEMORY_CONFIG, NULL, NULL),
|
||||
createOffTConfig("loading-process-events-interval-bytes", NULL, MODIFIABLE_CONFIG | HIDDEN_CONFIG, 1024, INT_MAX, server.loading_process_events_interval_bytes, 1024*1024*2, INTEGER_CONFIG, NULL, NULL),
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
createIntConfig("tls-port", NULL, MODIFIABLE_CONFIG, 0, 65535, server.tls_port, 0, INTEGER_CONFIG, NULL, applyTLSPort), /* TCP port. */
|
||||
createIntConfig("tls-session-cache-size", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.tls_ctx_config.session_cache_size, 20*1024, INTEGER_CONFIG, NULL, applyTlsCfg),
|
||||
createIntConfig("tls-session-cache-timeout", NULL, MODIFIABLE_CONFIG, 0, INT_MAX, server.tls_ctx_config.session_cache_timeout, 300, INTEGER_CONFIG, NULL, applyTlsCfg),
|
||||
@ -3130,7 +3127,6 @@ standardConfig static_configs[] = {
|
||||
createStringConfig("tls-protocols", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.protocols, NULL, NULL, applyTlsCfg),
|
||||
createStringConfig("tls-ciphers", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.ciphers, NULL, NULL, applyTlsCfg),
|
||||
createStringConfig("tls-ciphersuites", NULL, MODIFIABLE_CONFIG, EMPTY_STRING_IS_NULL, server.tls_ctx_config.ciphersuites, NULL, NULL, applyTlsCfg),
|
||||
#endif
|
||||
|
||||
/* Special configs */
|
||||
createSpecialConfig("dir", NULL, MODIFIABLE_CONFIG | PROTECTED_CONFIG | DENY_LOADING_CONFIG, setConfigDirOption, getConfigDirOption, rewriteConfigDirOption, NULL),
|
||||
|
102
src/connection.c
Normal file
102
src/connection.c
Normal file
@ -0,0 +1,102 @@
|
||||
/* ==========================================================================
|
||||
* connection.c - connection layer framework
|
||||
* --------------------------------------------------------------------------
|
||||
* Copyright (C) 2022 zhenwei pi
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
* persons to whom the Software is furnished to do so, subject to the
|
||||
* following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
* ==========================================================================
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
#include "connection.h"
|
||||
|
||||
static ConnectionType *connTypes[CONN_TYPE_MAX];
|
||||
|
||||
int connTypeRegister(ConnectionType *ct) {
|
||||
int type = ct->get_type(NULL);
|
||||
|
||||
/* unknown connection type as a fatal error */
|
||||
if (type >= CONN_TYPE_MAX) {
|
||||
serverPanic("Unsupported connection type %d", type);
|
||||
}
|
||||
|
||||
if (connTypes[type] == ct) {
|
||||
serverLog(LL_WARNING, "Connection type %d already registered", type);
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
serverLog(LL_VERBOSE, "Connection type %d registered", type);
|
||||
connTypes[type] = ct;
|
||||
|
||||
if (ct->init) {
|
||||
ct->init();
|
||||
}
|
||||
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
int connTypeInitialize() {
|
||||
/* currently socket connection type is necessary */
|
||||
serverAssert(RedisRegisterConnectionTypeSocket() == C_OK);
|
||||
|
||||
/* may fail if without BUILD_TLS=yes */
|
||||
RedisRegisterConnectionTypeTLS();
|
||||
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
ConnectionType *connectionByType(int type) {
|
||||
ConnectionType *ct;
|
||||
|
||||
serverAssert(type < CONN_TYPE_MAX);
|
||||
|
||||
ct = connTypes[type];
|
||||
if (!ct) {
|
||||
serverLog(LL_WARNING, "Missing implement of connection type %d", type);
|
||||
}
|
||||
|
||||
return ct;
|
||||
}
|
||||
|
||||
void connTypeCleanup(int type) {
|
||||
ConnectionType *ct = connectionByType(type);
|
||||
|
||||
if (ct && ct->cleanup) {
|
||||
ct->cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void connTypeCleanupAll() {
|
||||
int type;
|
||||
|
||||
for (type = 0; type < CONN_TYPE_MAX; type++) {
|
||||
connTypeCleanup(type);
|
||||
}
|
||||
}
|
||||
|
||||
int connTypeConfigure(int type, void *priv, int reconfigure) {
|
||||
ConnectionType *ct = connectionByType(type);
|
||||
|
||||
if (ct && ct->configure) {
|
||||
return ct->configure(priv, reconfigure);
|
||||
}
|
||||
|
||||
return C_ERR;
|
||||
}
|
@ -54,8 +54,9 @@ typedef enum {
|
||||
#define CONN_FLAG_CLOSE_SCHEDULED (1<<0) /* Closed scheduled by a handler */
|
||||
#define CONN_FLAG_WRITE_BARRIER (1<<1) /* Write barrier requested */
|
||||
|
||||
#define CONN_TYPE_SOCKET 1
|
||||
#define CONN_TYPE_TLS 2
|
||||
#define CONN_TYPE_SOCKET 0
|
||||
#define CONN_TYPE_TLS 1
|
||||
#define CONN_TYPE_MAX 2
|
||||
|
||||
typedef void (*ConnectionCallbackFunc)(struct connection *conn);
|
||||
|
||||
@ -63,6 +64,11 @@ typedef struct ConnectionType {
|
||||
/* connection type */
|
||||
int (*get_type)(struct connection *conn);
|
||||
|
||||
/* connection type initialize & finalize & configure */
|
||||
void (*init)(void); /* auto-call during register */
|
||||
void (*cleanup)(void);
|
||||
int (*configure)(void *priv, int reconfigure);
|
||||
|
||||
/* ae & accept & listen & error & address handler */
|
||||
void (*ae_handler)(struct aeEventLoop *el, int fd, void *clientData, int mask);
|
||||
int (*addr)(connection *conn, char *ip, size_t ip_len, int *port, int remote);
|
||||
@ -329,4 +335,24 @@ sds connTLSGetPeerCert(connection *conn);
|
||||
int tlsHasPendingData();
|
||||
int tlsProcessPendingData();
|
||||
|
||||
/* Initialize the redis connection framework */
|
||||
int connTypeInitialize();
|
||||
|
||||
/* Register a connection type into redis connection framework */
|
||||
int connTypeRegister(ConnectionType *ct);
|
||||
|
||||
/* Configure a connection type. A typical case is to configure TLS.
|
||||
* @priv is connection type specified,
|
||||
* @reconfigure is boolean type to specify if overwrite the original config */
|
||||
int connTypeConfigure(int type, void *priv, int reconfigure);
|
||||
|
||||
/* Cleanup a connection type. A typical case is to cleanup TLS. */
|
||||
void connTypeCleanup(int type);
|
||||
|
||||
/* Walk all the connection type, and cleanup them all if possible */
|
||||
void connTypeCleanupAll();
|
||||
|
||||
int RedisRegisterConnectionTypeSocket();
|
||||
int RedisRegisterConnectionTypeTLS();
|
||||
|
||||
#endif /* __REDIS_CONNECTION_H */
|
||||
|
@ -848,7 +848,7 @@ void sentinelRunPendingScripts(void) {
|
||||
sj->pid = 0;
|
||||
} else if (pid == 0) {
|
||||
/* Child */
|
||||
tlsCleanup();
|
||||
connTypeCleanupAll();
|
||||
execve(sj->argv[0],sj->argv,environ);
|
||||
/* If we are here an error occurred. */
|
||||
_exit(2); /* Don't retry execution. */
|
||||
|
@ -2447,7 +2447,7 @@ void initServer(void) {
|
||||
}
|
||||
|
||||
if ((server.tls_port || server.tls_replication || server.tls_cluster)
|
||||
&& tlsConfigure(&server.tls_ctx_config) == C_ERR) {
|
||||
&& connTypeConfigure(CONN_TYPE_TLS, &server.tls_ctx_config, 1) == C_ERR) {
|
||||
serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
|
||||
exit(1);
|
||||
}
|
||||
@ -6944,7 +6944,7 @@ int main(int argc, char **argv) {
|
||||
ACLInit(); /* The ACL subsystem must be initialized ASAP because the
|
||||
basic networking code and client creation depends on it. */
|
||||
moduleInitModulesSystem();
|
||||
tlsInit();
|
||||
connTypeInitialize();
|
||||
|
||||
/* Store the executable path and arguments in a safe place in order
|
||||
* to be able to restart the server later. */
|
||||
|
@ -3579,12 +3579,6 @@ void swapMainDbWithTempDb(redisDb *tempDb);
|
||||
_serverLog(level, __VA_ARGS__);\
|
||||
} while(0)
|
||||
|
||||
/* TLS stuff */
|
||||
void tlsInit(void);
|
||||
void tlsCleanup(void);
|
||||
int tlsConfigure(redisTLSContextConfig *ctx_config);
|
||||
int isTlsConfigured(void);
|
||||
|
||||
#define redisDebug(fmt, ...) \
|
||||
printf("DEBUG %s:%d > " fmt "\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define redisDebugMark() \
|
||||
|
@ -352,6 +352,11 @@ ConnectionType CT_Socket = {
|
||||
/* connection type */
|
||||
.get_type = connSocketGetType,
|
||||
|
||||
/* connection type initialize & finalize & configure */
|
||||
.init = NULL,
|
||||
.cleanup = NULL,
|
||||
.configure = NULL,
|
||||
|
||||
/* ae & accept & listen & error & address handler */
|
||||
.ae_handler = connSocketEventHandler,
|
||||
.addr = connSocketAddr,
|
||||
@ -409,3 +414,7 @@ int connRecvTimeout(connection *conn, long long ms) {
|
||||
return anetRecvTimeout(NULL, conn->fd, ms);
|
||||
}
|
||||
|
||||
int RedisRegisterConnectionTypeSocket()
|
||||
{
|
||||
return connTypeRegister(&CT_Socket);
|
||||
}
|
||||
|
42
src/tls.c
42
src/tls.c
@ -141,7 +141,7 @@ static void initCryptoLocks(void) {
|
||||
}
|
||||
#endif /* USE_CRYPTO_LOCKS */
|
||||
|
||||
void tlsInit(void) {
|
||||
static void tlsInit(void) {
|
||||
/* Enable configuring OpenSSL using the standard openssl.cnf
|
||||
* OPENSSL_config()/OPENSSL_init_crypto() should be the first
|
||||
* call to the OpenSSL* library.
|
||||
@ -169,7 +169,7 @@ void tlsInit(void) {
|
||||
pending_list = listCreate();
|
||||
}
|
||||
|
||||
void tlsCleanup(void) {
|
||||
static void tlsCleanup(void) {
|
||||
if (redis_tls_ctx) {
|
||||
SSL_CTX_free(redis_tls_ctx);
|
||||
redis_tls_ctx = NULL;
|
||||
@ -281,12 +281,20 @@ error:
|
||||
|
||||
/* Attempt to configure/reconfigure TLS. This operation is atomic and will
|
||||
* leave the SSL_CTX unchanged if fails.
|
||||
* @priv: config of redisTLSContextConfig.
|
||||
* @reconfigure: if true, ignore the previous configure; if false, only
|
||||
* configure from @ctx_config if redis_tls_ctx is NULL.
|
||||
*/
|
||||
int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
||||
static int tlsConfigure(void *priv, int reconfigure) {
|
||||
redisTLSContextConfig *ctx_config = (redisTLSContextConfig *)priv;
|
||||
char errbuf[256];
|
||||
SSL_CTX *ctx = NULL;
|
||||
SSL_CTX *client_ctx = NULL;
|
||||
|
||||
if (!reconfigure && redis_tls_ctx) {
|
||||
return C_OK;
|
||||
}
|
||||
|
||||
if (!ctx_config->cert_file) {
|
||||
serverLog(LL_WARNING, "No tls-cert-file configured!");
|
||||
goto error;
|
||||
@ -406,12 +414,6 @@ error:
|
||||
return C_ERR;
|
||||
}
|
||||
|
||||
/* Return 1 if TLS was already configured, 0 otherwise.
|
||||
*/
|
||||
int isTlsConfigured(void) {
|
||||
return redis_tls_ctx != NULL;
|
||||
}
|
||||
|
||||
#ifdef TLS_DEBUGGING
|
||||
#define TLSCONN_DEBUG(fmt, ...) \
|
||||
serverLog(LL_DEBUG, "TLSCONN: " fmt, __VA_ARGS__)
|
||||
@ -1066,6 +1068,11 @@ ConnectionType CT_TLS = {
|
||||
/* connection type */
|
||||
.get_type = connTLSGetType,
|
||||
|
||||
/* connection type initialize & finalize & configure */
|
||||
.init = tlsInit,
|
||||
.cleanup = tlsCleanup,
|
||||
.configure = tlsConfigure,
|
||||
|
||||
/* ae & accept & listen & error & address handler */
|
||||
.ae_handler = tlsEventHandler,
|
||||
.addr = connTLSAddr,
|
||||
@ -1090,17 +1097,16 @@ ConnectionType CT_TLS = {
|
||||
.sync_readline = connTLSSyncReadLine,
|
||||
};
|
||||
|
||||
int RedisRegisterConnectionTypeTLS()
|
||||
{
|
||||
return connTypeRegister(&CT_TLS);
|
||||
}
|
||||
|
||||
#else /* USE_OPENSSL */
|
||||
|
||||
void tlsInit(void) {
|
||||
}
|
||||
|
||||
void tlsCleanup(void) {
|
||||
}
|
||||
|
||||
int tlsConfigure(redisTLSContextConfig *ctx_config) {
|
||||
UNUSED(ctx_config);
|
||||
return C_OK;
|
||||
int RedisRegisterConnectionTypeTLS()
|
||||
{
|
||||
return C_ERR;
|
||||
}
|
||||
|
||||
connection *connCreateTLS(void) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user