diff --git a/README.md b/README.md index 479135c7a..569745e90 100644 --- a/README.md +++ b/README.md @@ -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). diff --git a/daemon/main.c b/daemon/main.c index 2d0206410..c7a655990 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -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"); diff --git a/daemon/redis.c b/daemon/redis.c index d193598e8..d4c906224 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -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++) { diff --git a/daemon/redis.h b/daemon/redis.h index 6961953db..6140e0244 100644 --- a/daemon/redis.h +++ b/daemon/redis.h @@ -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 *); diff --git a/debian/ngcp-rtpengine-daemon.default b/debian/ngcp-rtpengine-daemon.default index b341e198f..f9b56f89c 100644 --- a/debian/ngcp-rtpengine-daemon.default +++ b/debian/ngcp-rtpengine-daemon.default @@ -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 diff --git a/debian/ngcp-rtpengine-daemon.init b/debian/ngcp-rtpengine-daemon.init index 67b4347f7..f1bbfd885 100755 --- a/debian/ngcp-rtpengine-daemon.init +++ b/debian/ngcp-rtpengine-daemon.init @@ -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"