Skip to content

Commit b82b85b

Browse files
cachedb_redis: add TLS support
Closes OpenSIPS#2264
1 parent 4d672ae commit b82b85b

File tree

7 files changed

+212
-14
lines changed

7 files changed

+212
-14
lines changed

cachedb/cachedb_id.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828

2929
#include "../str.h"
3030

31+
#define CACHEDB_TLS_DOM_PARAM "tls_domain="
32+
#define CACHEDB_TLS_DOM_PARAM_LEN (sizeof(CACHEDB_TLS_DOM_PARAM)-1)
33+
3134
/** Structure representing a database ID */
3235
struct cachedb_id {
3336
char* scheme; /**< URL scheme */

modules/cachedb_redis/Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@ include ../../Makefile.defs
99
auto_gen=
1010
NAME=cachedb_redis.so
1111

12+
HAVE_REDIS_SSL=$(shell if [ -n "`ldconfig -p | grep hiredis_ssl`" ]; \
13+
then echo "HAVE_REDIS_SSL"; fi)
14+
ifeq ($(HAVE_REDIS_SSL), HAVE_REDIS_SSL)
15+
LIBS+=-lhiredis_ssl -lssl -lcrypto
16+
DEFS+= -DHAVE_REDIS_SSL
17+
endif
18+
1219
ifeq ($(CROSS_COMPILE),)
13-
LIBS=-lhiredis
20+
LIBS+=-lhiredis
1421
else
1522
DEFS+=-I$(LOCALBASE)/include
1623
LIBS=-L$(LOCALBASE)/lib -lhiredis

modules/cachedb_redis/cachedb_redis.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,27 @@ static param_export_t params[]={
5757
{ "query_timeout", INT_PARAM, &redis_query_tout },
5858
{ "shutdown_on_error", INT_PARAM, &shutdown_on_error },
5959
{ "cachedb_url", STR_PARAM|USE_FUNC_PARAM, (void *)&set_connection},
60+
{ "use_tls", INT_PARAM, &use_tls},
6061
{0,0,0}
6162
};
6263

64+
static module_dependency_t *get_deps_use_tls(param_export_t *param)
65+
{
66+
if (*(int *)param->param_pointer == 0)
67+
return NULL;
68+
69+
return alloc_module_dep(MOD_TYPE_DEFAULT, "tls_mgm", DEP_ABORT);
70+
}
71+
72+
static dep_export_t deps = {
73+
{
74+
{ MOD_TYPE_NULL, NULL, 0 },
75+
},
76+
{
77+
{ "use_tls", get_deps_use_tls },
78+
{ NULL, NULL },
79+
},
80+
};
6381

6482
/** module exports */
6583
struct module_exports exports= {
@@ -68,7 +86,7 @@ struct module_exports exports= {
6886
MODULE_VERSION,
6987
DEFAULT_DLFLAGS, /* dlopen flags */
7088
0, /* load function */
71-
NULL, /* OpenSIPS module dependencies */
89+
&deps, /* OpenSIPS module dependencies */
7290
0, /* exported functions */
7391
0, /* exported async functions */
7492
params, /* exported parameters */
@@ -115,6 +133,19 @@ static int mod_init(void)
115133
return -1;
116134
}
117135

136+
/* check if we have TLS support, as it is not built by defult in libhiredis */
137+
#ifndef HAVE_REDIS_SSL
138+
if (use_tls) {
139+
LM_NOTICE("Unable to use TLS connections as libhiredis was not "
140+
"compiled with TLS support!\n");
141+
use_tls = 0;
142+
}
143+
#endif
144+
if (use_tls && load_tls_mgm_api(&tls_api) != 0) {
145+
LM_ERR("failed to load tls_mgm API!\n");
146+
return -1;
147+
}
148+
118149
return 0;
119150
}
120151

modules/cachedb_redis/cachedb_redis_dbase.c

Lines changed: 102 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "cachedb_redis_utils.h"
2929
#include "../../mem/mem.h"
3030
#include "../../ut.h"
31+
#include "../../pt.h"
3132
#include "../../cachedb/cachedb.h"
3233

3334
#include <string.h>
@@ -38,6 +39,9 @@
3839
int redis_query_tout = CACHEDB_REDIS_DEFAULT_TIMEOUT;
3940
int redis_connnection_tout = CACHEDB_REDIS_DEFAULT_TIMEOUT;
4041
int shutdown_on_error = 0;
42+
int use_tls = 0;
43+
44+
struct tls_mgm_binds tls_api;
4145

4246
redisContext *redis_get_ctx(char *ip, int port)
4347
{
@@ -71,6 +75,64 @@ redisContext *redis_get_ctx(char *ip, int port)
7175
return ctx;
7276
}
7377

78+
#ifdef HAVE_REDIS_SSL
79+
static void tls_print_errstack(void)
80+
{
81+
int code;
82+
83+
while ((code = ERR_get_error())) {
84+
LM_ERR("TLS errstack: %s\n", ERR_error_string(code, 0));
85+
}
86+
}
87+
88+
static int redis_init_ssl(char *url_extra_opts, redisContext *ctx,
89+
struct tls_domain **tls_dom)
90+
{
91+
str tls_dom_name;
92+
SSL *ssl;
93+
94+
if (*tls_dom == NULL) {
95+
if (strncmp(url_extra_opts, CACHEDB_TLS_DOM_PARAM,
96+
CACHEDB_TLS_DOM_PARAM_LEN)) {
97+
LM_ERR("Invalid Redis URL parameter: %s\n", url_extra_opts);
98+
return -1;
99+
}
100+
101+
tls_dom_name.s = url_extra_opts + CACHEDB_TLS_DOM_PARAM_LEN;
102+
tls_dom_name.len = strlen(tls_dom_name.s);
103+
if (!tls_dom_name.len) {
104+
LM_ERR("Empty TLS domain name in Redis URL\n");
105+
return -1;
106+
}
107+
108+
*tls_dom = tls_api.find_client_domain_name(&tls_dom_name);
109+
if (*tls_dom == NULL) {
110+
LM_ERR("TLS domain: %.*s not found\n",
111+
tls_dom_name.len, tls_dom_name.s);
112+
return -1;
113+
}
114+
}
115+
116+
ssl = SSL_new((*tls_dom)->ctx[process_no]);
117+
if (!ssl) {
118+
LM_ERR("failed to create SSL structure (%d:%s)\n", errno, strerror(errno));
119+
tls_print_errstack();
120+
tls_api.release_domain(*tls_dom);
121+
return -1;
122+
}
123+
124+
if (redisInitiateSSL(ctx, ssl) != REDIS_OK) {
125+
printf("Failed to init Redis SSL: %s\n", ctx->errstr);
126+
tls_api.release_domain(*tls_dom);
127+
return -1;
128+
}
129+
130+
LM_DBG("TLS enabled for this connection\n");
131+
132+
return 0;
133+
}
134+
#endif
135+
74136
int redis_connect_node(redis_con *con,cluster_node *node)
75137
{
76138
redisReply *rpl;
@@ -79,14 +141,22 @@ int redis_connect_node(redis_con *con,cluster_node *node)
79141
if (!node->context)
80142
return -1;
81143

144+
#ifdef HAVE_REDIS_SSL
145+
if (use_tls && con->id->extra_options &&
146+
redis_init_ssl(con->id->extra_options, node->context,
147+
&node->tls_dom) < 0) {
148+
redisFree(node->context);
149+
return -1;
150+
}
151+
#endif
152+
82153
if (con->id->password) {
83154
rpl = redisCommand(node->context,"AUTH %s",con->id->password);
84155
if (rpl == NULL || rpl->type == REDIS_REPLY_ERROR) {
85156
LM_ERR("failed to auth to redis - %.*s\n",
86157
rpl?(unsigned)rpl->len:7,rpl?rpl->str:"FAILURE");
87158
freeReplyObject(rpl);
88-
redisFree(node->context);
89-
return -1;
159+
goto error;
90160
}
91161
LM_DBG("AUTH [password] - %.*s\n",(unsigned)rpl->len,rpl->str);
92162
freeReplyObject(rpl);
@@ -98,15 +168,22 @@ int redis_connect_node(redis_con *con,cluster_node *node)
98168
LM_ERR("failed to select database %s - %.*s\n",con->id->database,
99169
rpl?(unsigned)rpl->len:7,rpl?rpl->str:"FAILURE");
100170
freeReplyObject(rpl);
101-
redisFree(node->context);
102-
return -1;
171+
goto error;
103172
}
104173

105174
LM_DBG("SELECT [%s] - %.*s\n",con->id->database,(unsigned)rpl->len,rpl->str);
106175
freeReplyObject(rpl);
107176
}
108177

109178
return 0;
179+
180+
error:
181+
redisFree(node->context);
182+
if (use_tls && node->tls_dom) {
183+
tls_api.release_domain(node->tls_dom);
184+
node->tls_dom = NULL;
185+
}
186+
return -1;
110187
}
111188

112189
int redis_reconnect_node(redis_con *con,cluster_node *node)
@@ -120,19 +197,27 @@ int redis_reconnect_node(redis_con *con,cluster_node *node)
120197
return redis_connect_node(con,node);
121198
}
122199

123-
124200
int redis_connect(redis_con *con)
125201
{
126202
redisContext *ctx;
127203
redisReply *rpl;
128204
cluster_node *it;
129205
int len;
206+
struct tls_domain *tls_dom = NULL;
130207

131208
/* connect to redis DB */
132209
ctx = redis_get_ctx(con->id->host,con->id->port);
133210
if (!ctx)
134211
return -1;
135212

213+
#ifdef HAVE_REDIS_SSL
214+
if (use_tls && con->id->extra_options &&
215+
redis_init_ssl(con->id->extra_options, ctx, &tls_dom) < 0) {
216+
redisFree(ctx);
217+
return -1;
218+
}
219+
#endif
220+
136221
/* auth using password, if any */
137222
if (con->id->password) {
138223
rpl = redisCommand(ctx,"AUTH %s",con->id->password);
@@ -141,8 +226,7 @@ int redis_connect(redis_con *con)
141226
rpl?(unsigned)rpl->len:7,rpl?rpl->str:"FAILURE");
142227
if (rpl!=NULL)
143228
freeReplyObject(rpl);
144-
redisFree(ctx);
145-
return -1;
229+
goto error;
146230
}
147231
LM_DBG("AUTH [password] - %.*s\n",(unsigned)rpl->len,rpl->str);
148232
freeReplyObject(rpl);
@@ -158,8 +242,7 @@ int redis_connect(redis_con *con)
158242
LM_ERR("no more pkg\n");
159243
if (rpl!=NULL)
160244
freeReplyObject(rpl);
161-
redisFree(ctx);
162-
return -1;
245+
goto error;
163246
}
164247
con->nodes->ip = (char *)(con->nodes + 1);
165248

@@ -178,15 +261,17 @@ int redis_connect(redis_con *con)
178261
if (build_cluster_nodes(con,rpl->str,rpl->len) < 0) {
179262
LM_ERR("failed to parse Redis cluster info\n");
180263
freeReplyObject(rpl);
181-
redisFree(ctx);
182-
return -1;
264+
goto error;
183265
}
184266
}
185267

186268
if (rpl!=NULL)
187269
freeReplyObject(rpl);
188270
redisFree(ctx);
189271

272+
if (use_tls && tls_dom)
273+
tls_api.release_domain(tls_dom);
274+
190275
con->flags |= REDIS_INIT_NODES;
191276

192277
for (it=con->nodes;it;it=it->next) {
@@ -201,6 +286,12 @@ int redis_connect(redis_con *con)
201286
}
202287

203288
return 0;
289+
290+
error:
291+
redisFree(ctx);
292+
if (use_tls && tls_dom)
293+
tls_api.release_domain(tls_dom);
294+
return -1;
204295
}
205296

206297
redis_con* redis_new_connection(struct cachedb_id* id)

modules/cachedb_redis/cachedb_redis_dbase.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@
2828

2929
#include <hiredis/hiredis.h>
3030
#include "../../cachedb/cachedb.h"
31+
#include "../tls_mgm/api.h"
32+
33+
#ifdef HAVE_REDIS_SSL
34+
#include <hiredis/hiredis_ssl.h>
35+
#include <openssl/ssl.h>
36+
#include <openssl/err.h>
37+
#endif
3138

3239
typedef struct cluster_nodes {
3340
char *ip; /* ip of this cluster node */
@@ -36,6 +43,8 @@ typedef struct cluster_nodes {
3643
unsigned short end_slot; /* last slot for this server */
3744

3845
redisContext *context; /* actual connection to this node */
46+
struct tls_domain *tls_dom;
47+
3948
struct cluster_nodes *next;
4049
} cluster_node;
4150

@@ -45,6 +54,9 @@ typedef struct cluster_nodes {
4554
extern int redis_query_tout;
4655
extern int redis_connnection_tout;
4756
extern int shutdown_on_error;
57+
extern int use_tls;
58+
59+
extern struct tls_mgm_binds tls_api;
4860

4961
enum redis_flag {
5062
REDIS_SINGLE_INSTANCE = 1 << 0,

modules/cachedb_redis/cachedb_redis_utils.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ void destroy_cluster_nodes(redis_con *con)
110110
while (new) {
111111
foo = new->next;
112112
redisFree(new->context);
113+
if (use_tls && new->tls_dom)
114+
tls_api.release_domain(new->tls_dom);
113115
pkg_free(new);
114116
new = foo;
115117
}

0 commit comments

Comments
 (0)