support Redis server authentication

closes #219

Change-Id: Iacf4047e748d76ff402e44a1b9f22e1d7c511c76
changes/96/4596/1
Richard Fuchs 9 years ago
parent 3f1ae98379
commit c1407d6b44

@ -168,8 +168,8 @@ option and which are reproduced below:
-f, --foreground Don't fork to background
-m, --port-min=INT Lowest port to use for RTP
-M, --port-max=INT Highest port to use for RTP
-r, --redis=IP:PORT/INT Connect to Redis database
-w, --redis-write=IP:PORT/INT Connect to Redis write database
-r, --redis=[PW@]IP:PORT/INT Connect to Redis database
-w, --redis-write=[PW@]IP:PORT/INT Connect to Redis write database
-b, --b2b-url=STRING XMLRPC URL of B2B UA
-L, --log-level=INT Mask log priorities above this level
--log-facility=daemon|local0|... Syslog facility to use for logging
@ -358,6 +358,13 @@ The options are described in more detail below.
storage. The format of this option is `ADDRESS:PORT/DBNUM`, for example `127.0.0.1:6379/12`
to connect to the Redis DB number 12 running on localhost on the default Redis port.
If the Redis database is protected with an authentication password, the password can be supplied
by prefixing the argument value with the password, separated by an `@` symbol, for example
`foobar@127.0.0.1:6379/12`. Note that this leaves the password visible in the process list,
posing a security risk if untrusted users access the same system. As an alternative, the password
can also be supplied in the shell environment through the environment variable
`RTPENGINE_REDIS_AUTH_PW`.
On startup, *rtpengine* will read the contents of this database and restore all calls
stored therein. During runtime operation, *rtpengine* will continually update the database's
contents to keep it current, so that in case of a service disruption, the last state can be restored
@ -372,6 +379,9 @@ The options are described in more detail below.
first one, then the first database will be used for read operations (i.e. to restore calls from) while
the second one will be used for write operations (to update states in the database).
For password protected Redis servers, the environment variable for the password is
`RTPENGINE_REDIS_WRITE_AUTH_PW`.
When both options are given, *rtpengine* will start and use the Redis database regardless of the
database's role (master or slave).

@ -71,6 +71,8 @@ static int port_max = 40000;
static int max_sessions = -1;
static int redis_db = -1;
static int redis_write_db = -1;
static char *redis_auth;
static char *redis_write_auth;
static char *b2b_url;
static enum xmlrpc_format xmlrpc_fmt = XF_SEMS;
static int num_threads;
@ -215,10 +217,19 @@ static struct intf_config *if_addr_parse(char *s) {
static int redis_ep_parse(endpoint_t *ep, int *db, char *str) {
static int redis_ep_parse(endpoint_t *ep, int *db, char **auth, const char *auth_env, char *str) {
char *sl;
long l;
sl = strchr(str, '@');
if (sl) {
*sl = 0;
*auth = str;
str = sl+1;
}
else if ((sl = getenv(auth_env)))
*auth = sl;
sl = strchr(str, '/');
if (!sl)
return -1;
@ -276,8 +287,8 @@ static void options(int *argc, char ***argv) {
{ "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Don't fork to background", NULL },
{ "port-min", 'm', 0, G_OPTION_ARG_INT, &port_min, "Lowest port to use for RTP", "INT" },
{ "port-max", 'M', 0, G_OPTION_ARG_INT, &port_max, "Highest port to use for RTP", "INT" },
{ "redis", 'r', 0, G_OPTION_ARG_STRING, &redisps, "Connect to Redis database", "IP:PORT/INT" },
{ "redis-write",'w', 0, G_OPTION_ARG_STRING, &redisps_write, "Connect to Redis write database", "IP:PORT/INT" },
{ "redis", 'r', 0, G_OPTION_ARG_STRING, &redisps, "Connect to Redis database", "[PW@]IP:PORT/INT" },
{ "redis-write",'w', 0, G_OPTION_ARG_STRING, &redisps_write, "Connect to Redis write database", "[PW@]IP:PORT/INT" },
{ "b2b-url", 'b', 0, G_OPTION_ARG_STRING, &b2b_url, "XMLRPC URL of B2B UA" , "STRING" },
{ "log-level", 'L', 0, G_OPTION_ARG_INT, (void *)&log_level,"Mask log priorities above this level","INT" },
{ "log-facility",0, 0, G_OPTION_ARG_STRING, &log_facility_s, "Syslog facility to use for logging", "daemon|local0|...|local7"},
@ -349,11 +360,12 @@ static void options(int *argc, char ***argv) {
silent_timeout = 3600;
if (redisps)
if (redis_ep_parse(&redis_ep, &redis_db, redisps))
if (redis_ep_parse(&redis_ep, &redis_db, &redis_auth, "RTPENGINE_REDIS_AUTH_PW", redisps))
die("Invalid Redis endpoint [IP:PORT/INT] (--redis)");
if (redisps_write)
if (redis_ep_parse(&redis_write_ep, &redis_write_db, redisps_write))
if (redis_ep_parse(&redis_write_ep, &redis_write_db, &redis_write_auth,
"RTPENGINE_REDIS_WRITE_AUTH_PW", redisps_write))
die("Invalid Redis endpoint [IP:PORT/INT] (--redis-write)");
if (xmlrpc_fmt > 1)
@ -559,13 +571,13 @@ no_kernel:
}
if (!is_addr_unspecified(&redis_write_ep.address)) {
mc.redis_write = redis_new(&redis_write_ep, redis_write_db, ANY_REDIS_ROLE);
mc.redis_write = redis_new(&redis_write_ep, redis_write_db, redis_write_auth, ANY_REDIS_ROLE);
if (!mc.redis_write)
die("Cannot start up without Redis write database");
}
if (!is_addr_unspecified(&redis_ep.address)) {
mc.redis = redis_new(&redis_ep, redis_db, mc.redis_write ? ANY_REDIS_ROLE : MASTER_REDIS_ROLE);
mc.redis = redis_new(&redis_ep, redis_db, redis_auth, mc.redis_write ? ANY_REDIS_ROLE : MASTER_REDIS_ROLE);
if (!mc.redis)
die("Cannot start up without Redis database");

@ -142,8 +142,14 @@ static int redis_connect(struct redis *r, int wait) {
if (r->ctx->err)
goto err2;
if (redisCommandNR(r->ctx, "PING"))
goto err2;
if (r->auth) {
if (redisCommandNR(r->ctx, "AUTH %s", r->auth))
goto err2;
}
else {
if (redisCommandNR(r->ctx, "PING"))
goto err2;
}
if (redisCommandNR(r->ctx, "SELECT %i", r->db))
goto err2;
@ -206,7 +212,7 @@ err:
struct redis *redis_new(const endpoint_t *ep, int db, enum redis_role role) {
struct redis *redis_new(const endpoint_t *ep, int db, const char *auth, enum redis_role role) {
struct redis *r;
r = g_slice_alloc0(sizeof(*r));
@ -214,6 +220,7 @@ struct redis *redis_new(const endpoint_t *ep, int db, enum redis_role role) {
r->endpoint = *ep;
sockaddr_print(&ep->address, r->host, sizeof(r->host));
r->db = db;
r->auth = auth;
r->role = role;
mutex_init(&r->lock);
@ -1074,7 +1081,7 @@ int redis_restore(struct callmaster *m, struct redis *r) {
mutex_init(&ctx.r_m);
g_queue_init(&ctx.r_q);
for (i = 0; i < RESTORE_NUM_THREADS; i++)
g_queue_push_tail(&ctx.r_q, redis_new(&r->endpoint, r->db, r->role));
g_queue_push_tail(&ctx.r_q, redis_new(&r->endpoint, r->db, r->auth, r->role));
gtp = g_thread_pool_new(restore_thread, &ctx, RESTORE_NUM_THREADS, TRUE, NULL);
for (i = 0; i < calls->elements; i++) {

@ -32,6 +32,7 @@ struct redis {
redisContext *ctx;
int db;
const char *auth;
mutex_t lock;
unsigned int pipeline;
};
@ -78,7 +79,7 @@ INLINE gboolean g_hash_table_insert_check(GHashTable *h, gpointer k, gpointer v)
struct redis *redis_new(const endpoint_t *, int, enum redis_role);
struct redis *redis_new(const endpoint_t *, int, const char *, enum redis_role);
int redis_restore(struct callmaster *, struct redis *);
void redis_update(struct call *, struct redis *);
void redis_delete(struct call *, struct redis *);

@ -17,8 +17,10 @@ TABLE=0
# PORT_MAX=50000
# REDIS=127.0.0.1:6379
# REDIS_DB=1
# REDIS_AUTH_PW=foobar
# REDIS_WRITE=127.0.0.1:6379
# REDIS_WRITE_DB=1
# REDIS_WRITE_AUTH_PW=foobar
# B2B_URL=http://127.0.0.1:8090/
# LOG_LEVEL=6
# LOG_FACILITY=daemon

@ -63,7 +63,9 @@ fi
[ -z "$PORT_MIN" ] || OPTIONS="$OPTIONS --port-min=$PORT_MIN"
[ -z "$PORT_MAX" ] || OPTIONS="$OPTIONS --port-max=$PORT_MAX"
[ -z "$REDIS" -o -z "$REDIS_DB" ] || OPTIONS="$OPTIONS --redis=$REDIS/$REDIS_DB"
[ -z "$REDIS_AUTH_PW" ] || export RTPENGINE_REDIS_AUTH_PW="$REDIS_AUTH_PW"
[ -z "$REDIS_WRITE" -o -z "$REDIS_WRITE_DB" ] || OPTIONS="$OPTIONS --redis-write=$REDIS_WRITE/$REDIS_WRITE_DB"
[ -z "$REDIS_WRITE_AUTH_PW" ] || export RTPENGINE_REDIS_WRITE_AUTH_PW="$REDIS_WRITE_AUTH_PW"
[ -z "$B2B_URL" ] || OPTIONS="$OPTIONS --b2b-url=$B2B_URL"
[ -z "$NO_FALLBACK" -o \( "$NO_FALLBACK" != "1" -a "$NO_FALLBACK" != "yes" \) ] || OPTIONS="$OPTIONS --no-fallback"
OPTIONS="$OPTIONS --table=$TABLE"

Loading…
Cancel
Save