From f1c25e7d77dd9811fa93ebea57f3ff2c82fcacce Mon Sep 17 00:00:00 2001 From: Simone Mainardi Date: Thu, 11 Aug 2016 11:34:36 +0200 Subject: [PATCH] Implements Redis-authentication Implements #685 --- include/Prefs.h | 2 ++ include/Redis.h | 5 ++++- src/Ntop.cpp | 4 +++- src/Prefs.cpp | 53 ++++++++++++++++++++++++++++++++----------------- src/Redis.cpp | 19 ++++++++++++++---- 5 files changed, 59 insertions(+), 24 deletions(-) diff --git a/include/Prefs.h b/include/Prefs.h index 5fd0afa945..282395397e 100644 --- a/include/Prefs.h +++ b/include/Prefs.h @@ -71,6 +71,7 @@ class Prefs { char *packet_filter; char *user; char *redis_host; + char *redis_password; char *pid_path; char *cpu_affinity; u_int8_t redis_db_id; @@ -153,6 +154,7 @@ class Prefs { inline u_int get_http_port() { return(http_port); }; inline u_int get_https_port() { return(https_port); }; inline char* get_redis_host() { return(redis_host); } + inline char* get_redis_password() { return(redis_password); } inline u_int get_redis_port() { return(redis_port); }; inline u_int get_redis_db_id() { return(redis_db_id); }; inline char* get_pid_path() { return(pid_path); }; diff --git a/include/Redis.h b/include/Redis.h index 7c2eb1026a..cc9630fa48 100644 --- a/include/Redis.h +++ b/include/Redis.h @@ -31,6 +31,7 @@ class Redis { redisContext *redis; Mutex *l; char *redis_host; + char *redis_password; u_int16_t redis_port; u_int8_t redis_db_id; pthread_t esThreadLoop; @@ -46,7 +47,9 @@ class Redis { int popHost(const char* ns_list, char *hostname, u_int hostname_len); public: - Redis(char *redis_host = (char*)"127.0.0.1", u_int16_t redis_port = 6379, u_int8_t _redis_db_id = 0); + Redis(char *redis_host = (char*)"127.0.0.1", + char *redis_password = NULL, + u_int16_t redis_port = 6379, u_int8_t _redis_db_id = 0); ~Redis(); char* getVersion(char *str, u_int str_len); diff --git a/src/Ntop.cpp b/src/Ntop.cpp index ddc90325e2..47bfffec2e 100644 --- a/src/Ntop.cpp +++ b/src/Ntop.cpp @@ -236,7 +236,9 @@ void Ntop::registerNagios(void) { void Ntop::initRedis() { if(redis) delete(redis); - redis = new Redis(prefs->get_redis_host(), prefs->get_redis_port(), prefs->get_redis_db_id()); + redis = new Redis(prefs->get_redis_host(), + prefs->get_redis_password(), + prefs->get_redis_port(), prefs->get_redis_db_id()); } /* ******************************************* */ diff --git a/src/Prefs.cpp b/src/Prefs.cpp index b5273a0498..e0b0248610 100755 --- a/src/Prefs.cpp +++ b/src/Prefs.cpp @@ -53,6 +53,7 @@ Prefs::Prefs(Ntop *_ntop) { httpbl_key = NULL, flashstart = NULL; cpu_affinity = NULL; redis_host = strdup("127.0.0.1"); + redis_password = NULL; redis_port = 6379; redis_db_id = 0; dns_mode = 0; @@ -126,8 +127,9 @@ Prefs::~Prefs() { if(instance_name) free(instance_name); free(http_prefix); - free(redis_host); free(local_networks); + free(redis_host); + if(redis_password) free(redis_password); if(cli) free(cli); if(mysql_host) free(mysql_host); if(mysql_dbname) free(mysql_dbname); @@ -206,7 +208,18 @@ void usage() { "[--ndpi-protocols|-p] .protos | Specify a nDPI protocol file\n" " | (eg. protos.txt)\n" "[--disable-host-persistency|-P] | Disable host persistency in the Redis cache\n" - "[--redis|-r] | Redis host[:port][@database id]\n" + "[--redis|-r] | Redis connection. is [h[:port[:pwd]]][@db-id]\n" + " | db-id is the identifier of the redis database (default 0).\n" + " | h is the host that is running the Redis server (default\n" + " | localhost), and is optionally followed by a ':'-separated\n" + " | port (default 6379). A password can be specified after\n" + " | the port when Redis authentication is required.\n" + " | By default password authentication is disabled.\n" + " | Examples:\n" + " | -r @2\n" + " | -r 129.168.1.3\n" + " | -r 129.168.1.3:6379@3\n" + " | -r 129.168.1.3:6379:nt0pngPwD@0\n" #ifdef linux "[--core-affinity|-g] | Bind the capture/processing threads to\n" " | specific CPU cores (specified as a comma-\n" @@ -702,33 +715,37 @@ int Prefs::setOption(int optkey, char *optarg) { host:port@redis_instance */ snprintf(buf, sizeof(buf), "%s", optarg); - r = strtok(buf, "@"); + r = strrchr(buf, '@'); if(r) { - char *c; + redis_db_id = atoi((const char*)&r[1]); + (*r) = '\0'; + } - if(strchr(r, ':')) { - char *w; + if(strchr(buf, ':')) { + char *w, *c; - c = strtok_r(r, ":", &w); + c = strtok_r(buf, ":", &w); - if(redis_host) free(redis_host); - redis_host = strdup(c); + if(redis_host) free(redis_host); + redis_host = strdup(c); - c = strtok_r(NULL, ":", &w); - if(c) redis_port = atoi(c); - } else { - if(redis_host) free(redis_host); - redis_host = strdup(r); - } + c = strtok_r(NULL, ":", &w); + if(c) redis_port = atoi(c); - c = strtok(NULL, "@"); - if(c != NULL) - redis_db_id = atoi((const char*)c); + c = strtok_r(NULL, ":", &w); + if(c) redis_password = strdup(c); + } else if (strlen(buf) > 0) { + /* only the host */ + if(redis_host) free(redis_host); + redis_host = strdup(buf); } ntop->getTrace()->traceEvent(TRACE_NORMAL, "ntopng will use redis %s:%u@%u", redis_host, redis_port, redis_db_id); + if (redis_password) + ntop->getTrace()->traceEvent(TRACE_NORMAL, + "redis connection is password-protected"); } break; diff --git a/src/Redis.cpp b/src/Redis.cpp index b097dc7c0c..831a37f5f7 100644 --- a/src/Redis.cpp +++ b/src/Redis.cpp @@ -29,8 +29,9 @@ /* **************************************** */ -Redis::Redis(char *_redis_host, u_int16_t _redis_port, u_int8_t _redis_db_id) { - redis_host = _redis_host, redis_port= _redis_port, redis_db_id = _redis_db_id; +Redis::Redis(char *_redis_host, char *_redis_password, u_int16_t _redis_port, u_int8_t _redis_db_id) { + redis_host = _redis_host, redis_password = _redis_password; + redis_port = _redis_port, redis_db_id = _redis_db_id; redis = NULL, operational = false; reconnectRedis(); @@ -63,8 +64,17 @@ void Redis::reconnectRedis() { redis = redisConnectWithTimeout(redis_host, redis_port, timeout); - while(num_attemps > 0) { - if(redis) reply = (redisReply*)redisCommand(redis, "PING"); else reply = NULL; + if(redis_password) { + reply = (redisReply*)redisCommand(redis, "AUTH %s", redis_password); + if(reply && (reply->type == REDIS_REPLY_ERROR)) { + ntop->getTrace()->traceEvent(TRACE_ERROR, + "Redis authentication failed: %s", reply->str ? reply->str : "???"); + goto redis_error_handler; + } + } + + while(redis && num_attemps > 0) { + reply = (redisReply*)redisCommand(redis, "PING"); if(reply && (reply->type == REDIS_REPLY_ERROR)) { ntop->getTrace()->traceEvent(TRACE_ERROR, "%s", reply->str ? reply->str : "???"); sleep(1); @@ -83,6 +93,7 @@ void Redis::reconnectRedis() { } else { freeReplyObject(reply); + reply = (redisReply*)redisCommand(redis, "SELECT %u", redis_db_id); if(reply && (reply->type == REDIS_REPLY_ERROR)) { ntop->getTrace()->traceEvent(TRACE_ERROR, "%s", reply->str ? reply->str : "???");