36 #include <sys/types.h> 40 #include <hiredis/hiredis.h> 46 #define G_LOG_DOMAIN "lib kb_redis" 59 #define GLOBAL_DBINDEX_NAME "OpenVAS.__GlobalDBIndex" 65 #define KB_RETRY_DELAY 60 84 #define redis_kb(__kb) ((struct kb_redis *)(__kb)) 96 static int redis_delete_all (
struct kb_redis *);
97 static int redis_lnk_reset (
kb_t);
98 static int redis_flush_all (
kb_t,
const char *);
99 static redisReply *redis_cmd (
struct kb_redis *kbr,
const char *fmt, ...)
100 __attribute__((__format__(__printf__, 2, 3)));
107 try_database_index (struct
kb_redis *kbr,
int index)
109 redisContext *ctx = kbr->rctx;
117 if (rep->type != REDIS_REPLY_INTEGER)
119 else if (rep->integer == 0)
124 freeReplyObject (rep);
135 #define MAX_DB_INDEX__24 1000 138 fetch_max_db_index_compat (
struct kb_redis *kbr)
140 redisContext *ctx = kbr->
rctx;
152 current = min + ((
max - min) / 2);
154 rep = redisCommand (ctx,
"SELECT %d", current);
158 "%s: redis command failed with '%s'", __func__, ctx->errstr);
164 case REDIS_REPLY_ERROR:
168 case REDIS_REPLY_STATUS:
174 "%s: unexpected reply of type %d", __func__, rep->type);
175 freeReplyObject (rep);
178 freeReplyObject (rep);
184 rep = redisCommand (ctx,
"SELECT 0");
188 "%s: DB selection failed with '%s'", __func__, ctx->errstr);
193 freeReplyObject (rep);
199 fetch_max_db_index (
struct kb_redis *kbr)
202 redisContext *ctx = kbr->
rctx;
203 redisReply *rep = NULL;
205 rep = redisCommand (ctx,
"CONFIG GET databases");
209 "%s: redis command failed with '%s'", __func__, ctx->errstr);
214 if (rep->type != REDIS_REPLY_ARRAY)
217 "%s: cannot retrieve max DB number: %s", __func__, rep->str);
222 if (rep->elements == 0)
225 rc = fetch_max_db_index_compat (kbr);
227 else if (rep->elements == 2)
229 kbr->
max_db = (unsigned)atoi(rep->element[1]->str);
234 "%s: unexpected reply length (%zd)", __func__, rep->elements);
239 g_debug (
"%s: maximum DB number: %u", __func__, kbr->
max_db);
243 freeReplyObject (rep);
253 select_database (
struct kb_redis *kbr)
256 redisContext *ctx = kbr->
rctx;
257 redisReply *rep = NULL;
264 fetch_max_db_index (kbr);
266 for (i = 1; i < kbr->
max_db; i++)
268 rc = try_database_index (kbr, i);
281 rep = redisCommand (ctx,
"SELECT %u", kbr->
db);
282 if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
292 freeReplyObject (rep);
298 redis_release_db (
struct kb_redis *kbr)
301 redisContext *ctx = kbr->
rctx;
307 rep = redisCommand (ctx,
"SELECT 0");
308 if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
313 freeReplyObject (rep);
316 if (rep == NULL || rep->type != REDIS_REPLY_INTEGER)
326 freeReplyObject (rep);
331 static redisContext *
332 get_redis_ctx (
struct kb_redis *kbr)
336 if (kbr->
rctx != NULL)
341 kbr->
rctx = redisConnectUnix (kbr->
path);
342 if (kbr->
rctx == NULL || kbr->
rctx->err)
345 "%s: redis connection error: %s", __func__,
346 kbr->
rctx ? kbr->
rctx->errstr : strerror (ENOMEM));
347 redisFree (kbr->
rctx);
352 rc = select_database (kbr);
355 g_debug (
"%s: No redis DB available, retrying in %ds...", __func__,
358 redisFree (kbr->
rctx);
364 g_debug (
"%s: connected to redis://%s/%d", __func__, kbr->
path, kbr->
db);
369 redis_test_connection (
struct kb_redis *kbr)
374 rep = redis_cmd (kbr,
"PING");
383 if (rep->type != REDIS_REPLY_STATUS)
389 if (g_ascii_strcasecmp (rep->str,
"PONG"))
397 freeReplyObject (rep);
409 redis_delete_all (kbr);
410 redis_release_db (kbr);
412 if (kbr->
rctx != NULL)
414 redisFree (kbr->
rctx);
423 redis_new (
kb_t *
kb,
const char *kb_path)
428 kbr = g_malloc0 (
sizeof (
struct kb_redis) + strlen (kb_path) + 1);
429 kbr->
kb.
kb_ops = &KBRedisOperations;
430 strcpy (kbr->
path, kb_path);
432 rc = redis_test_connection (kbr);
436 "%s: cannot access redis at '%s'", __func__, kb_path);
437 redis_delete ((
kb_t)kbr);
447 redis_find (
const char *kb_path,
const char *key)
453 kbr = g_malloc0 (
sizeof (
struct kb_redis) + strlen (kb_path) + 1);
454 kbr->
kb.
kb_ops = &KBRedisOperations;
455 strncpy (kbr->
path, kb_path, strlen (kb_path));
459 kbr->
rctx = redisConnectUnix (kbr->
path);
460 if (kbr->
rctx == NULL || kbr->
rctx->err)
463 "%s: redis connection error: %s", __func__,
464 kbr->
rctx ? kbr->
rctx->errstr : strerror (ENOMEM));
465 redisFree (kbr->
rctx);
472 if (rep == NULL || rep->type != REDIS_REPLY_INTEGER || rep->integer != 1)
475 freeReplyObject (rep);
479 freeReplyObject (rep);
480 rep = redisCommand (kbr->
rctx,
"SELECT %u", i);
481 if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
488 freeReplyObject (rep);
489 if (key && kb_item_get_int (&kbr->
kb, key) > 0)
492 redisFree (kbr->
rctx);
509 g_free (item->
v_str);
520 redisReply *rep = NULL;
526 redis_lnk_reset ((
kb_t)kbr);
528 ctx = get_redis_ctx (kbr);
532 rep = redisCommand (ctx,
"MULTI");
533 if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
543 freeReplyObject (rep);
549 redis_transaction_cmd (
struct redis_tx *rtx,
const char *fmt, ...)
560 rep = redisvCommand (rtx->
kbr->
rctx, fmt, ap);
561 if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
574 freeReplyObject (rep);
580 redis_transaction_end (
struct redis_tx *rtx, redisReply **rep)
590 preply = redisCommand (rtx->
kbr->
rctx,
"EXEC");
591 if (preply == NULL || preply->type == REDIS_REPLY_ERROR)
604 freeReplyObject (preply);
608 memset (rtx, 0,
sizeof (
struct redis_tx));
614 redis2kbitem_single (
const char *
name,
const redisReply *elt,
int force_int)
619 if (elt->type != REDIS_REPLY_STRING && elt->type != REDIS_REPLY_INTEGER)
625 if (elt->type == REDIS_REPLY_INTEGER)
628 item->
v_int = elt->integer;
633 item->
v_int = atoi (elt->str);
638 item->
v_str = g_strdup (elt->str);
649 redis2kbitem (
const char *
name,
const redisReply *rep)
659 case REDIS_REPLY_STRING:
660 case REDIS_REPLY_INTEGER:
661 kbi = redis2kbitem_single (
name, rep, 0);
664 case REDIS_REPLY_ARRAY:
665 for (i = 0; i < rep->elements; i++)
669 tmpitem = redis2kbitem_single (
name, rep->element[i], 0);
683 case REDIS_REPLY_NIL:
684 case REDIS_REPLY_STATUS:
685 case REDIS_REPLY_ERROR:
694 redis_cmd (
struct kb_redis *kbr,
const char *fmt, ...)
707 ctx = get_redis_ctx (kbr);
715 rep = redisvCommand (ctx, fmt, aq);
721 freeReplyObject (rep);
723 redis_lnk_reset ((
kb_t)kbr);
746 rep = redis_cmd (kbr,
"SRANDMEMBER %s",
name);
747 if (rep == NULL || rep->type != REDIS_REPLY_STRING)
757 freeReplyObject (rep);
805 rep = redis_cmd (kbr,
"LINDEX nvt:%s %d",
oid, position);
808 if (rep->type == REDIS_REPLY_INTEGER)
809 res = g_strdup_printf (
"%lld", rep->integer);
810 else if (rep->type == REDIS_REPLY_STRING)
811 res = g_strdup (rep->str);
812 freeReplyObject (rep);
826 rep = redis_cmd (kbr,
"SMEMBERS %s",
name);
830 kbi = redis2kbitem (
name, rep);
832 freeReplyObject (rep);
838 redis_get_pattern (
kb_t kb,
const char *pattern)
848 rep = redis_cmd (kbr,
"KEYS %s", pattern);
852 if (rep->type != REDIS_REPLY_ARRAY)
854 freeReplyObject (rep);
858 for (i = 0; i < rep->elements; i++)
862 redisReply *rep_range;
864 key = rep->element[i]->str;
866 rep_range = redis_cmd (kbr,
"SMEMBERS %s", key);
867 if (rep_range == NULL)
870 tmp = redis2kbitem (key, rep_range);
879 while (tmp->
next != NULL)
889 if (rep_range != NULL)
890 freeReplyObject (rep_range);
893 freeReplyObject (rep);
899 redis_count (
kb_t kb,
const char *pattern)
907 rep = redis_cmd (kbr,
"KEYS %s", pattern);
911 if (rep->type != REDIS_REPLY_ARRAY)
913 freeReplyObject (rep);
917 count = rep->elements;
918 freeReplyObject (rep);
931 rep = redis_cmd (kbr,
"DEL %s",
name);
932 if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
936 freeReplyObject (rep);
942 redis_add_str (
kb_t kb,
const char *
name,
const char *str)
950 rep = redis_cmd (kbr,
"SADD %s %s",
name, str);
951 if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
955 freeReplyObject (rep);
971 rc = redis_transaction_new (
kbr, &rtx);
978 redis_transaction_cmd (&rtx,
"DEL %s",
name);
979 redis_transaction_cmd (&rtx,
"SADD %s %s",
name,
val);
981 rc = redis_transaction_end (&rtx, &rep);
982 if (rc || rep == NULL || rep->type == REDIS_REPLY_ERROR)
990 freeReplyObject (rep);
1004 rep = redis_cmd (kbr,
"SADD %s %d",
name,
val);
1005 if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
1013 freeReplyObject (rep);
1029 rc = redis_transaction_new (
kbr, &rtx);
1036 redis_transaction_cmd (&rtx,
"DEL %s",
name);
1037 redis_transaction_cmd (&rtx,
"SADD %s %d",
name,
val);
1039 rc = redis_transaction_end (&rtx, &rep);
1040 if (rc || rep == NULL || rep->type == REDIS_REPLY_ERROR)
1048 freeReplyObject (rep);
1054 redis_add_nvt (
kb_t kb,
const nvti_t *nvt,
const char *filename)
1057 redisReply *rep = NULL;
1060 if (!nvt || !filename)
1064 rep = redis_cmd (kbr,
1065 "RPUSH nvt:%s %s %s %s %s %s %s %s %s %s %s %s %d %d %s %s" 1077 if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
1080 freeReplyObject (rep);
1082 rep = redis_cmd (kbr,
"SADD filename:%s:oid %s", filename,
nvti_oid (nvt));
1083 if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
1086 freeReplyObject (rep);
1092 redis_lnk_reset (
kb_t kb)
1098 if (kbr->
rctx != NULL)
1100 redisFree (kbr->
rctx);
1108 redis_flush_all (
kb_t kb,
const char *except)
1116 redisFree (kbr->
rctx);
1118 g_debug (
"%s: deleting all DBs at %s except %s", __func__, kbr->
path, except);
1121 kbr->
rctx = redisConnectUnix (kbr->
path);
1122 if (kbr->
rctx == NULL || kbr->
rctx->err)
1125 "%s: redis connection error: %s", __func__,
1126 kbr->
rctx ? kbr->
rctx->errstr : strerror (ENOMEM));
1127 redisFree (kbr->
rctx);
1134 if (rep == NULL || rep->type != REDIS_REPLY_INTEGER || rep->integer != 1)
1136 freeReplyObject (rep);
1137 redisFree (kbr->
rctx);
1141 freeReplyObject (rep);
1142 rep = redisCommand (kbr->
rctx,
"SELECT %u", i);
1143 if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
1145 freeReplyObject (rep);
1147 redisFree (kbr->
rctx);
1152 freeReplyObject (rep);
1154 if (except && kb_item_get_int (
kb, except) > 0)
1157 redisFree (kbr->
rctx);
1160 redis_delete_all (kbr);
1161 redis_release_db (kbr);
1162 redisFree (kbr->
rctx);
1173 redis_delete_all (
struct kb_redis *kbr)
1177 struct sigaction new_action, original_action;
1180 new_action.sa_flags = 0;
1181 if (sigemptyset (&new_action.sa_mask))
1183 new_action.sa_handler = SIG_IGN;
1184 if (sigaction (SIGPIPE, &new_action, &original_action))
1187 g_debug (
"%s: deleting all elements from KB #%u", __func__, kbr->
db);
1188 rep = redis_cmd (kbr,
"FLUSHDB");
1189 if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
1198 if (sigaction (SIGPIPE, &original_action, NULL))
1201 freeReplyObject (rep);
1209 .kb_find = redis_find,
1210 .kb_delete = redis_delete,
1211 .kb_get_single = redis_get_single,
1212 .kb_get_str = redis_get_str,
1213 .kb_get_int = redis_get_int,
1214 .kb_get_nvt = redis_get_nvt,
1215 .kb_get_all = redis_get_all,
1216 .kb_get_pattern = redis_get_pattern,
1217 .kb_count = redis_count,
1218 .kb_add_str = redis_add_str,
1219 .kb_set_str = redis_set_str,
1220 .kb_add_int = redis_add_int,
1221 .kb_set_int = redis_set_int,
1222 .kb_add_nvt = redis_add_nvt,
1223 .kb_del_items = redis_del_items,
1224 .kb_lnk_reset = redis_lnk_reset,
1225 .kb_flush = redis_flush_all,
kb_nvt_pos
Possible positions of nvt values in cache list.
gchar * nvti_xref(const nvti_t *n)
Get the xref's.
#define GLOBAL_DBINDEX_NAME
Name of the namespace usage bitmap in redis.
gchar * nvti_required_ports(const nvti_t *n)
Get the required ports list.
gchar * nvti_copyright(const nvti_t *n)
Get the copyright notice.
gchar * nvti_cve(const nvti_t *n)
Get the CVE references.
The structure of a information record that corresponds to a NVT.
Knowledge base item (defined by name, type (int/char*) and value). Implemented as a singly linked lis...
KB interface. Functions provided by an implementation. All functions have to be provided, there is no default/fallback. These functions should be called via the corresponding static inline wrappers below. See the wrappers for the documentation.
gint nvti_category(const nvti_t *n)
Get the category for this NVT.
gint nvti_timeout(const nvti_t *n)
Get the timeout for this NVT.
gchar * nvti_tag(const nvti_t *n)
Get the tag.
#define KB_RETRY_DELAY
Number of seconds to wait for between two attempts to acquire a KB namespace.
gchar * nvti_family(const nvti_t *n)
Get the family name.
gchar * nvti_dependencies(const nvti_t *n)
Get the dependencies list.
gchar * nvti_excluded_keys(const nvti_t *n)
Get the excluded keys list.
gchar * nvti_mandatory_keys(const nvti_t *n)
Get the mandatory keys list.
Top-level KB. This is to be inherited by KB implementations.
const struct kb_operations * kb_ops
Redis transaction handle.
void kb_item_free(struct kb_item *item)
Release a KB item (or a list).
gchar * nvti_required_udp_ports(const nvti_t *n)
Get the required udp ports list.
kb_item_type
Possible type of a kb_item.
Subclass of struct kb, it contains the redis-specific fields, such as the redis context, current DB (namespace) id and the server socket path.
struct kb * kb_t
type abstraction to hide KB internals.
gchar * nvti_required_keys(const nvti_t *n)
Get the required keys list.
gchar * nvti_oid(const nvti_t *n)
Get the OID string.
gchar * nvti_bid(const nvti_t *n)
Get the bid references.
gchar * nvti_version(const nvti_t *n)
Get the version.
const struct kb_operations * KBDefaultOperations
Default KB operations. No selection mechanism is provided yet since there's only one implementation (...
int(* kb_new)(kb_t *, const char *)
gchar * nvti_name(const nvti_t *n)
Get the name.