1818 *
1919 * Author: Brian Knox
2020 * <bknox@digitalocean.com>
21+ *
22+ * Author: Jérémie Jourdin (TLS support)
23+ * <jeremie.jourdin@advens.fr>
2124 */
2225
2326
3235#include <time.h>
3336#include <math.h>
3437#include <hiredis/hiredis.h>
38+ #ifdef HIREDIS_SSL
39+ #include <hiredis/hiredis_ssl.h>
40+ #endif
3541
3642#include "rsyslog.h"
3743#include "conf.h"
@@ -94,13 +100,25 @@ typedef struct _instanceData {
94100 - $.redis!index
95101 Those 2 infos can either be provided through usage of imhiredis
96102 or set manually with Rainerscript */
103+ #ifdef HIREDIS_SSL
104+ sbool use_tls ; /* Should we use TLS to connect to redis ? */
105+ char * ca_cert_bundle ; /* CA bundle file */
106+ char * ca_cert_dir ; /* Path of trusted certificates */
107+ char * client_cert ; /* Client certificate */
108+ char * client_key ; /* Client private key */
109+ char * sni ; /* TLS Server Name Indication */
110+ #endif
97111
98112} instanceData ;
99113
100114typedef struct wrkrInstanceData {
101115 instanceData * pData ; /* instanc data */
102116 redisContext * conn ; /* redis connection */
103117 int count ; /* count of command sent for current batch */
118+ #ifdef HIREDIS_SSL
119+ redisSSLContext * ssl_conn ; /* redis ssl connection */
120+ redisSSLContextError ssl_error ; /* ssl error handler */
121+ #endif
104122} wrkrInstanceData_t ;
105123
106124static struct cnfparamdescr actpdescr [] = {
@@ -124,6 +142,14 @@ static struct cnfparamdescr actpdescr[] = {
124142 {"stream.dynaKeyAck" , eCmdHdlrBinary , 0 },
125143 {"stream.dynaGroupAck" , eCmdHdlrBinary , 0 },
126144 {"stream.dynaIndexAck" , eCmdHdlrBinary , 0 },
145+ #ifdef HIREDIS_SSL
146+ {"use_tls" , eCmdHdlrBinary , 0 },
147+ {"ca_cert_bundle" , eCmdHdlrGetWord , 0 },
148+ {"ca_cert_dir" , eCmdHdlrGetWord , 0 },
149+ {"client_cert" , eCmdHdlrGetWord , 0 },
150+ {"client_key" , eCmdHdlrGetWord , 0 },
151+ {"sni" , eCmdHdlrGetWord , 0 },
152+ #endif
127153};
128154
129155static struct cnfparamblk actpblk = {CNFPARAMBLK_VERSION , sizeof (actpdescr ) / sizeof (struct cnfparamdescr ), actpdescr };
@@ -135,6 +161,10 @@ ENDcreateInstance
135161BEGINcreateWrkrInstance
136162 CODESTARTcreateWrkrInstance ;
137163 pWrkrData -> conn = NULL ; /* Connect later */
164+ #ifdef HIREDIS_SSL
165+ pWrkrData -> ssl_conn = NULL ; /* Connect later */
166+ pWrkrData -> ssl_error = REDIS_SSL_CTX_NONE ;
167+ #endif
138168ENDcreateWrkrInstance
139169
140170BEGINisCompatibleWithFeature
@@ -148,6 +178,12 @@ static void closeHiredis(wrkrInstanceData_t *pWrkrData) {
148178 redisFree (pWrkrData -> conn );
149179 pWrkrData -> conn = NULL ;
150180 }
181+ #ifdef HIREDIS_SSL
182+ if (pWrkrData -> ssl_conn != NULL ) {
183+ redisFreeSSLContext (pWrkrData -> ssl_conn );
184+ pWrkrData -> ssl_conn = NULL ;
185+ }
186+ #endif
151187}
152188
153189/* Free our instance data. */
@@ -167,6 +203,13 @@ BEGINfreeInstance
167203 free (pData -> streamGroupAck );
168204 free (pData -> streamIndexAck );
169205 free (pData -> streamOutField );
206+ #ifdef HIREDIS_SSL
207+ free (pData -> ca_cert_bundle );
208+ free (pData -> ca_cert_dir );
209+ free (pData -> client_cert );
210+ free (pData -> client_key );
211+ free (pData -> sni );
212+ #endif
170213ENDfreeInstance
171214
172215BEGINfreeWrkrInstance
@@ -220,6 +263,24 @@ static rsRetVal initHiredis(wrkrInstanceData_t *pWrkrData, int bSilent) {
220263 ABORT_FINALIZE (RS_RET_SUSPENDED );
221264 }
222265
266+ #ifdef HIREDIS_SSL
267+ if (pWrkrData -> pData -> use_tls ) {
268+ pWrkrData -> ssl_conn = redisCreateSSLContext (pWrkrData -> pData -> ca_cert_bundle , pWrkrData -> pData -> ca_cert_dir ,
269+ pWrkrData -> pData -> client_cert , pWrkrData -> pData -> client_key ,
270+ pWrkrData -> pData -> sni , & pWrkrData -> ssl_error );
271+ if (!pWrkrData -> ssl_conn || pWrkrData -> ssl_error != REDIS_SSL_CTX_NONE ) {
272+ LogError (0 , NO_ERRCODE , "omhiredis: SSL Context error: %s" , redisSSLContextGetError (pWrkrData -> ssl_error ));
273+ if (!bSilent ) LogError (0 , RS_RET_SUSPENDED , "[TLS] can not initialize redis handle" );
274+ ABORT_FINALIZE (RS_RET_SUSPENDED );
275+ }
276+ if (redisInitiateSSLWithContext (pWrkrData -> conn , pWrkrData -> ssl_conn ) != REDIS_OK ) {
277+ LogError (0 , NO_ERRCODE , "omhiredis: %s" , pWrkrData -> conn -> errstr );
278+ if (!bSilent ) LogError (0 , RS_RET_SUSPENDED , "[TLS] can not initialize redis handle" );
279+ ABORT_FINALIZE (RS_RET_SUSPENDED );
280+ }
281+ }
282+ #endif
283+
223284 if (pWrkrData -> pData -> serverpassword != NULL ) {
224285 reply = redisCommand (pWrkrData -> conn , "AUTH %s" , (char * )pWrkrData -> pData -> serverpassword );
225286 if (reply == NULL ) {
@@ -236,6 +297,12 @@ static rsRetVal initHiredis(wrkrInstanceData_t *pWrkrData, int bSilent) {
236297 redisFree (pWrkrData -> conn );
237298 pWrkrData -> conn = NULL ;
238299 }
300+ #ifdef HIREDIS_SSL
301+ if (iRet != RS_RET_OK && pWrkrData -> ssl_conn != NULL ) {
302+ redisFreeSSLContext (pWrkrData -> ssl_conn );
303+ pWrkrData -> ssl_conn = NULL ;
304+ }
305+ #endif
239306 if (reply != NULL ) freeReplyObject (reply );
240307 RETiRet ;
241308}
@@ -476,6 +543,14 @@ static void setInstParamDefaults(instanceData *pData) {
476543 pData -> streamCapacityLimit = 0 ;
477544 pData -> streamAck = 0 ;
478545 pData -> streamDel = 0 ;
546+ #ifdef HIREDIS_SSL
547+ pData -> use_tls = 0 ;
548+ pData -> ca_cert_bundle = NULL ;
549+ pData -> ca_cert_dir = NULL ;
550+ pData -> client_cert = NULL ;
551+ pData -> client_key = NULL ;
552+ pData -> sni = NULL ;
553+ #endif
479554}
480555
481556/* here is where the work to set up a new instance
@@ -551,6 +626,20 @@ BEGINnewActInst
551626 } else if (!strcmp (actpblk .descr [i ].name , "expiration" )) {
552627 pData -> expiration = pvals [i ].val .d .n ;
553628 dbgprintf ("omhiredis: expiration set to %d\n" , pData -> expiration );
629+ #ifdef HIREDIS_SSL
630+ } else if (!strcmp (actpblk .descr [i ].name , "use_tls" )) {
631+ pData -> use_tls = pvals [i ].val .d .n ;
632+ } else if (!strcmp (actpblk .descr [i ].name , "ca_cert_bundle" )) {
633+ pData -> ca_cert_bundle = (char * )es_str2cstr (pvals [i ].val .d .estr , NULL );
634+ } else if (!strcmp (actpblk .descr [i ].name , "ca_cert_dir" )) {
635+ pData -> ca_cert_dir = (char * )es_str2cstr (pvals [i ].val .d .estr , NULL );
636+ } else if (!strcmp (actpblk .descr [i ].name , "client_cert" )) {
637+ pData -> client_cert = (char * )es_str2cstr (pvals [i ].val .d .estr , NULL );
638+ } else if (!strcmp (actpblk .descr [i ].name , "client_key" )) {
639+ pData -> client_key = (char * )es_str2cstr (pvals [i ].val .d .estr , NULL );
640+ } else if (!strcmp (actpblk .descr [i ].name , "sni" )) {
641+ pData -> sni = (char * )es_str2cstr (pvals [i ].val .d .estr , NULL );
642+ #endif
554643 } else {
555644 dbgprintf (
556645 "omhiredis: program error, non-handled "
@@ -777,4 +866,9 @@ BEGINmodInit()
777866 ABORT_FINALIZE (RS_RET_ERR );
778867 }
779868 DBGPRINTF ("omhiredis: module compiled with rsyslog version %s.\n" , VERSION );
869+
870+ #ifdef HIREDIS_SSL
871+ // initialize OpenSSL
872+ redisInitOpenSSL ();
873+ #endif
780874ENDmodInit
0 commit comments