Skip to content

Commit

Permalink
Add support for TLS in omhiredis
Browse files Browse the repository at this point in the history
  • Loading branch information
Jérémie Jourdin committed Jul 30, 2024
1 parent 2e1786a commit a3b523a
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 4 deletions.
32 changes: 31 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2611,16 +2611,46 @@ if test "x$enable_omhiredis" = "xyes" -o "x$enable_imhiredis" = "xyes" ; then
[AC_MSG_ERROR([hiredis not found])]
)]
)
PKG_CHECK_MODULES(HIREDIS_SSL, hiredis_ssl >= 0.10.1,
# hiredis_ssl found
[
AC_DEFINE(HIREDIS_SSL, 1, [TLS support enabled in hiredis])
],
[AC_SEARCH_LIBS(redisCreateSSLContext, hiredis_ssl,
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[ #include <hiredis/hiredis.h>
#include <hiredis/hiredis_ssl.h>
]],
[[ #define major 0
#define minor 10
#define patch 1
#if (( HIREDIS_MAJOR > major ) || \
(( HIREDIS_MAJOR == major ) && ( HIREDIS_MINOR > minor )) || \
(( HIREDIS_MAJOR == major ) && ( HIREDIS_MINOR == minor ) && ( HIREDIS_PATCH >= patch ))) \
/* OK */
#else
# error Hiredis_ssl version must be >= major.minor.path
#endif
]]
)],
[],
[AC_MSG_ERROR([hiredis_ssl version must be >= 0.10.1])]
)],
[AC_MSG_WARN([hiredis_ssl not found, no TLS support in hiredis])]
)]
)
fi

if test "x$enable_imhiredis" = "xyes" ; then
PKG_CHECK_MODULES(LIBEVENT, [libevent >= 2.0, libevent_pthreads],
# libevent found
[
HIREDIS_LIBS="$HIREDIS_LIBS -levent -levent_pthreads"
HIREDIS_LIBS="$HIREDIS_LIBS $HIREDIS_SSL_LIBS -levent -levent_pthreads"
],
# libevent not found
[AC_MSG_ERROR([no libevent >= 2.0 found with pthreads support, imhiredis cannot use pub/sub])])

fi

if test "x$enable_imhiredis" = "xyes" || test "x$enable_omhiredis" = "xyes"; then
Expand Down
4 changes: 2 additions & 2 deletions contrib/omhiredis/Makefile.am
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pkglib_LTLIBRARIES = omhiredis.la
omhiredis_la_SOURCES = omhiredis.c
omhiredis_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(HIREDIS_CFLAGS)
omhiredis_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(HIREDIS_CFLAGS) $(HIREDIS_SSL_CFLAGS)
omhiredis_la_LDFLAGS = -module -avoid-version
omhiredis_la_LIBADD = $(HIREDIS_LIBS)
omhiredis_la_LIBADD = $(HIREDIS_LIBS) $(HIREDIS_SSL_LIBS)

EXTRA_DIST =
93 changes: 92 additions & 1 deletion contrib/omhiredis/omhiredis.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
*
* Author: Brian Knox
* <[email protected]>
*
* Author: Jérémie Jourdin (TLS support)
* <[email protected]>
*/


Expand All @@ -32,6 +35,9 @@
#include <time.h>
#include <math.h>
#include <hiredis/hiredis.h>
#ifdef HIREDIS_SSL
#include <hiredis/hiredis_ssl.h>
#endif

#include "rsyslog.h"
#include "conf.h"
Expand Down Expand Up @@ -93,13 +99,23 @@ typedef struct _instanceData {
- $.redis!index
Those 2 infos can either be provided through usage of imhiredis
or set manually with Rainerscript */
sbool use_tls; /* Should we use TLS to connect to redis ? */
char *ca_cert_bundle; /* CA bundle file */
char *ca_cert_dir; /* Path of trusted certificates */
char *client_cert; /* Client certificate */
char *client_key; /* Client private key */
char *sni; /* TLS Server Name Indication */

} instanceData;

typedef struct wrkrInstanceData {
instanceData *pData; /* instanc data */
redisContext *conn; /* redis connection */
int count; /* count of command sent for current batch */
#ifdef HIREDIS_SSL
redisSSLContext *ssl_conn; /* redis ssl connection */
redisSSLContextError ssl_error; /* ssl error handler */
#endif
} wrkrInstanceData_t;

static struct cnfparamdescr actpdescr[] = {
Expand All @@ -122,6 +138,14 @@ static struct cnfparamdescr actpdescr[] = {
{ "stream.dynaKeyAck", eCmdHdlrBinary, 0 },
{ "stream.dynaGroupAck", eCmdHdlrBinary, 0 },
{ "stream.dynaIndexAck", eCmdHdlrBinary, 0 },
#ifdef HIREDIS_SSL
{ "use_tls", eCmdHdlrBinary, 0 },
{ "ca_cert_bundle", eCmdHdlrGetWord, 0 },
{ "ca_cert_dir", eCmdHdlrGetWord, 0 },
{ "client_cert", eCmdHdlrGetWord, 0 },
{ "client_key", eCmdHdlrGetWord, 0 },
{ "sni", eCmdHdlrGetWord, 0 },
#endif
};

static struct cnfparamblk actpblk = {
Expand All @@ -137,6 +161,10 @@ ENDcreateInstance
BEGINcreateWrkrInstance
CODESTARTcreateWrkrInstance
pWrkrData->conn = NULL; /* Connect later */
#ifdef HIREDIS_SSL
pWrkrData->ssl_conn = NULL; /* Connect later */
pWrkrData->ssl_error = REDIS_SSL_CTX_NONE;
#endif
ENDcreateWrkrInstance

BEGINisCompatibleWithFeature
Expand All @@ -152,6 +180,12 @@ static void closeHiredis(wrkrInstanceData_t *pWrkrData)
redisFree(pWrkrData->conn);
pWrkrData->conn = NULL;
}
#ifdef HIREDIS_SSL
if(pWrkrData->ssl_conn != NULL) {
redisFreeSSLContext(pWrkrData->ssl_conn);
pWrkrData->ssl_conn = NULL;
}
#endif
}

/* Free our instance data. */
Expand All @@ -168,6 +202,13 @@ CODESTARTfreeInstance
free(pData->streamGroupAck);
free(pData->streamIndexAck);
free(pData->streamOutField);
#ifdef HIREDIS_SSL
free(pData->ca_cert_bundle);
free(pData->ca_cert_dir);
free(pData->client_cert);
free(pData->client_key);
free(pData->sni);
#endif
ENDfreeInstance

BEGINfreeWrkrInstance
Expand Down Expand Up @@ -195,13 +236,35 @@ static rsRetVal initHiredis(wrkrInstanceData_t *pWrkrData, int bSilent)
struct timeval timeout = { 1, 500000 }; /* 1.5 seconds */
pWrkrData->conn = redisConnectWithTimeout(server, pWrkrData->pData->port,
timeout);
if (pWrkrData->conn->err) {
if (pWrkrData->conn == NULL || pWrkrData->conn->err) {
if(!bSilent)
LogError(0, RS_RET_SUSPENDED,
"can not initialize redis handle");
ABORT_FINALIZE(RS_RET_SUSPENDED);
}

#ifdef HIREDIS_SSL
if (pWrkrData->pData->use_tls) {
redisInitOpenSSL();
pWrkrData->ssl_conn = redisCreateSSLContext(pWrkrData->pData->ca_cert_bundle, pWrkrData->pData->ca_cert_dir, pWrkrData->pData->client_cert, pWrkrData->pData->client_key, pWrkrData->pData->sni, &pWrkrData->ssl_error);
if (!pWrkrData->ssl_conn || pWrkrData->ssl_error != REDIS_SSL_CTX_NONE) {
LogError(0, NO_ERRCODE, "omhiredis: SSL Context error: %s", redisSSLContextGetError(pWrkrData->ssl_error));
if(!bSilent)
LogError(0, RS_RET_SUSPENDED,
"[TLS] can not initialize redis handle");
ABORT_FINALIZE(RS_RET_SUSPENDED);
}
if (redisInitiateSSLWithContext(pWrkrData->conn, pWrkrData->ssl_conn) != REDIS_OK) {
LogError(0, NO_ERRCODE, "omhiredis: %s", pWrkrData->conn->errstr);
LogError(0, NO_ERRCODE, "omhiredis: SSL Context error: %s", redisSSLContextGetError(pWrkrData->ssl_error));
if(!bSilent)
LogError(0, RS_RET_SUSPENDED,
"[TLS] can not initialize redis handle");
ABORT_FINALIZE(RS_RET_SUSPENDED);
}
}
#endif

if (pWrkrData->pData->serverpassword != NULL) {
reply = redisCommand(pWrkrData->conn, "AUTH %s", (char*) pWrkrData->pData->serverpassword);
if (reply == NULL) {
Expand All @@ -219,6 +282,12 @@ static rsRetVal initHiredis(wrkrInstanceData_t *pWrkrData, int bSilent)
redisFree(pWrkrData->conn);
pWrkrData->conn = NULL;
}
#ifdef HIREDIS_SSL
if (iRet != RS_RET_OK && pWrkrData-> ssl_conn != NULL) {
redisFreeSSLContext(pWrkrData->ssl_conn);
pWrkrData->ssl_conn = NULL;
}
#endif
if (reply != NULL) freeReplyObject(reply);
RETiRet;
}
Expand Down Expand Up @@ -470,6 +539,14 @@ setInstParamDefaults(instanceData *pData)
pData->streamCapacityLimit = 0;
pData->streamAck = 0;
pData->streamDel = 0;
#ifdef HIREDIS_SSL
pData->use_tls = 0;
pData->ca_cert_bundle = NULL;
pData->ca_cert_dir = NULL;
pData->client_cert = NULL;
pData->client_key = NULL;
pData->sni = NULL;
#endif
}

/* here is where the work to set up a new instance
Expand Down Expand Up @@ -545,6 +622,20 @@ CODESTARTnewActInst
} else if(!strcmp(actpblk.descr[i].name, "expiration")) {
pData->expiration = pvals[i].val.d.n;
dbgprintf("omhiredis: expiration set to %d\n", pData->expiration);
#ifdef HIREDIS_SSL
} else if(!strcmp(actpblk.descr[i].name, "use_tls")) {
pData->use_tls = pvals[i].val.d.n;
} else if(!strcmp(actpblk.descr[i].name, "ca_cert_bundle")) {
pData->ca_cert_bundle = (char*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(actpblk.descr[i].name, "ca_cert_dir")) {
pData->ca_cert_dir = (char*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(actpblk.descr[i].name, "client_cert")) {
pData->client_cert = (char*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(actpblk.descr[i].name, "client_key")) {
pData->client_key = (char*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(actpblk.descr[i].name, "sni")) {
pData->sni = (char*)es_str2cstr(pvals[i].val.d.estr, NULL);
#endif
} else {
dbgprintf("omhiredis: program error, non-handled "
"param '%s'\n", actpblk.descr[i].name);
Expand Down

0 comments on commit a3b523a

Please sign in to comment.