Coverage Report

Created: 2026-10-28 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ntopng/fuzz/stub/RedisStub.cpp
Line
Count
Source
1
/*
2
 *
3
 * (C) 2013-23 - ntop.org
4
 *
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software Foundation,
18
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
 *
20
 */
21
22
#include "ntop_includes.h"
23
24
Redis::Redis(const char* redis_host,
25
       const char* redis_password, u_int16_t redis_port,
26
       u_int8_t _redis_db_id, bool giveup_on_failure,
27
       const char* tls_ca_cert, const char* tls_cert,
28
20
       const char* tls_key, bool tls_skip_verify) {
29
20
  this->redisVersion = "RedisStub";
30
20
  this->localToResolve =
31
20
    std::make_unique<StringFifoQueue>(MAX_NUM_QUEUED_ADDRS);
32
20
  this->remoteToResolve =
33
20
    std::make_unique<StringFifoQueue>(MAX_NUM_QUEUED_ADDRS);
34
35
20
  memset(&stats, 0, sizeof(stats));
36
20
}
37
38
15
bool Redis::checkList(std::string key) {
39
15
  return (this->store.find(key) == this->store.end() &&
40
15
    this->setStore.find(key) == this->setStore.end());
41
15
}
42
43
0
bool Redis::checkSet(std::string key) {
44
0
  return (this->store.find(key) == this->store.end() &&
45
0
    this->listStore.find(key) == this->listStore.end());
46
0
}
47
48
0
char *Redis::getVersion() { return (char *)this->redisVersion.c_str(); }
49
50
0
u_int32_t Redis::getNumVersion() { return 1; }
51
52
0
bool Redis::hasRedisDump() { return false; }
53
54
10
void Redis::setDefaults() {}
55
56
6
bool Redis::isOperational() { return true; }
57
58
10
void Redis::setInitializationComplete() {}
59
60
0
int Redis::info(char *rsp, u_int rsp_len) {
61
0
  if (rsp_len == 0) return -1;
62
63
0
  stats.num_other++;
64
0
  if(rsp_len == 0)
65
0
    return -1;
66
    
67
0
  rsp[0] = 0;
68
0
  return 0;
69
0
}
70
71
0
u_int Redis::dbsize() {
72
0
  stats.num_other++;
73
0
  return this->store.size();
74
0
}
75
76
0
int Redis::expire(char *key, u_int expire_sec) {
77
0
  stats.num_expire++;
78
0
  return 0;
79
0
}
80
81
0
char* Redis::getWithAlloc(char *key, bool cache_it) {
82
0
  char *ret = NULL;
83
84
0
  stats.num_get++;
85
0
  std::string strKey(key);
86
0
  if (this->store.find(strKey) != this->store.end()) {
87
0
    ret = strdup(this->store[strKey].c_str());
88
0
  }
89
90
0
  return ret;
91
0
}
92
93
int Redis::get(char *key, char *rsp, u_int rsp_len,
94
59.2k
               bool cache_it /* = false */) {
95
59.2k
  if (rsp_len == 0) return -1;
96
97
59.2k
  stats.num_get++;
98
59.2k
  std::string strKey(key);
99
59.2k
  if (this->store.find(strKey) == this->store.end() ||
100
59.2k
      snprintf(rsp, rsp_len, "%s", this->store[strKey].c_str()) < 0) {
101
59.2k
    rsp[0] = 0;
102
59.2k
    return -1;
103
59.2k
  }
104
105
0
  return 0;
106
59.2k
}
107
108
0
char* Redis::getset(const char *key, const char *value, u_int expire_secs) {
109
0
  stats.num_get++;
110
0
  std::string strKey(key);
111
0
  char *old_value = NULL;
112
113
0
  if (this->store.find(strKey) != this->store.end())
114
0
    old_value = strdup(this->store[strKey].c_str());
115
116
0
  this->store[strKey] = std::string(value);
117
118
0
  return old_value;
119
0
}
120
121
int Redis::hashGet(const char *key, const char *member, char *const rsp,
122
4.69k
                   u_int rsp_len) {
123
4.69k
  if (rsp_len == 0) return -1;
124
125
4.69k
  std::stringstream ss;
126
4.69k
  ss << key << "@" << member;
127
4.69k
  std::string strKey = ss.str();
128
4.69k
  if (this->store.find(strKey) == this->store.end() ||
129
4.65k
      snprintf(rsp, rsp_len, "%s", this->store[strKey].c_str()) < 0) {
130
44
    rsp[0] = 0;
131
44
    return -1;
132
44
  }
133
134
4.65k
  return 0;
135
4.69k
}
136
137
0
int Redis::hashDel(const char *key, const char *field) {
138
0
  std::stringstream ss;
139
0
  ss << key << "@" << field;
140
0
  std::string strKey = ss.str();
141
0
  this->store.erase(strKey);
142
0
  return 0;
143
0
}
144
145
687k
int Redis::hashSet(const char *key, const char *field, const char *value) {
146
687k
  std::stringstream ss;
147
687k
  ss << key << "@" << field;
148
687k
  std::string strKey = ss.str();
149
687k
  this->store[strKey] = std::string(value);
150
687k
  return 0;
151
687k
}
152
153
int Redis::set(const char *key, const char *value,
154
4.29k
               u_int expire_secs /* = 0 */) {
155
4.29k
  std::string strKey(key);
156
4.29k
  this->store[strKey] = std::string(value);
157
4.29k
  return 0;
158
4.29k
}
159
160
/* setnx = set if not existing */
161
int Redis::setnx(const char *key, const char *value,
162
0
                 u_int expire_secs /* = 0 */) {
163
0
  std::string strKey(key);
164
0
  if (this->store.find(strKey) != this->store.end()) return -1;
165
166
0
  this->store[strKey] = std::string(value);
167
0
  return 0;
168
0
}
169
170
6
int Redis::keys(const char *pattern, char ***keys_p) {
171
6
  *keys_p = NULL;
172
6
  return 0;
173
6
}
174
175
0
int Redis::hashKeys(const char *pattern, char ***keys_p) {
176
0
  *keys_p = NULL;
177
0
  return 0;
178
0
}
179
180
9.33k
int Redis::hashGetAll(const char *key, char ***keys_p, char ***values_p) {
181
9.33k
  *keys_p = NULL;
182
9.33k
  return 0;
183
9.33k
}
184
185
6
int Redis::del(char *key) {
186
6
  std::string strKey(key);
187
6
  stats.num_del++;
188
6
  this->store.erase(strKey);
189
6
  return 0;
190
6
}
191
192
0
int Redis::rename(char *key, char *new_key) {
193
0
  return 0;
194
0
}
195
196
int Redis::pushHostToResolve(char *hostname, bool dont_check_for_existence,
197
1.74k
                             bool localHost) {
198
1.74k
  if (!ntop->getPrefs()->is_dns_resolution_enabled()) return 0;
199
1.74k
  if (hostname == NULL) return -1;
200
201
1.74k
  if (!Utils::shouldResolveHost(hostname)) return -1;
202
203
1.74k
  std::stringstream ss;
204
1.74k
  ss << DNS_CACHE << "." << hostname;
205
1.74k
  std::string strKey = ss.str();
206
207
  /* Add only if the address has not been resolved yet */
208
1.74k
  if (dont_check_for_existence ||
209
1.74k
      this->store.find(strKey) == this->store.end()) {
210
1.74k
    auto &q = localHost ? localToResolve : remoteToResolve;
211
1.74k
    q->enqueue(hostname);
212
213
1.74k
    return 0;
214
1.74k
  }
215
216
0
  return -1;
217
1.74k
}
218
219
0
int Redis::popHostToResolve(char *hostname, u_int hostname_len) {
220
0
  char *item = localToResolve->dequeue();
221
0
  int rv = -1;
222
223
0
  if (!item) item = remoteToResolve->dequeue();
224
225
0
  if (item) {
226
0
    strncpy(hostname, item, hostname_len);
227
0
    hostname[hostname_len - 1] = 0;
228
0
    free(item);
229
0
    rv = 0;
230
0
  }
231
232
0
  return rv;
233
0
}
234
235
int Redis::getAddress(char *numeric_ip, char *rsp, u_int rsp_len,
236
1.74k
                      bool queue_if_not_found) {
237
1.74k
  if (rsp_len == 0) return -1;
238
239
1.74k
  int rc;
240
1.74k
  char key[CONST_MAX_LEN_REDIS_KEY];
241
1.74k
  bool already_in_bloom;
242
243
1.74k
  rsp[0] = 0;
244
1.74k
  snprintf(key, sizeof(key), "%s.%s", DNS_CACHE, numeric_ip);
245
246
1.74k
  if (!ntop->getResolutionBloom()->isSetBit(numeric_ip)) {
247
1.74k
    already_in_bloom = false;
248
1.74k
    rc = -1; /* No way to find it */
249
1.74k
  } else {
250
0
    already_in_bloom = true;
251
0
    rc = this->get(key, rsp, rsp_len);
252
0
  }
253
254
1.74k
  if (rc != 0) {
255
1.74k
    if (queue_if_not_found) {
256
1.74k
      if (already_in_bloom)
257
0
  ntop->getResolutionBloom()->unsetBit(
258
0
               numeric_ip); /* Expired key ? */
259
260
1.74k
      this->pushHostToResolve(numeric_ip, true, false);
261
1.74k
    }
262
1.74k
  } else {
263
    /* We need to extend expire */
264
0
    if (!already_in_bloom)
265
0
      ntop->getResolutionBloom()->setBit(
266
0
           numeric_ip); /* Previously cached ? */
267
268
0
    this->expire(key, DNS_CACHE_DURATION /* expire */);
269
0
  }
270
271
1.74k
  return rc;
272
1.74k
}
273
274
0
int Redis::setResolvedAddress(char *numeric_ip, char *symbolic_ip) {
275
0
  char key[CONST_MAX_LEN_REDIS_KEY], numeric[256], *w, *h;
276
0
  int rc = 0;
277
278
0
  snprintf(numeric, sizeof(numeric), "%s", numeric_ip);
279
280
0
  h = strtok_r(numeric, ";", &w);
281
282
0
  while (h != NULL) {
283
0
    snprintf(key, sizeof(key), "%s.%s", DNS_CACHE, h);
284
0
    ntop->getResolutionBloom()->setBit(h);
285
0
    rc = this->set(key, symbolic_ip, DNS_CACHE_DURATION);
286
0
    h = strtok_r(NULL, ";", &w);
287
0
  }
288
289
0
  return rc;
290
0
}
291
292
0
int Redis::sadd(const char *set_name, char *item) {
293
0
  std::string strKey(set_name);
294
0
  if (!this->checkSet(strKey)) return -1;
295
0
  if (this->setStore.find(strKey) == this->setStore.end())
296
0
    this->setStore[strKey] = std::set<std::string>();
297
298
0
  auto result = this->setStore[strKey].insert(std::string(item));
299
0
  return (result.second ? 1 : 0);
300
0
}
301
302
0
int Redis::srem(const char *set_name, char *item) {
303
0
  std::string strKey(set_name);
304
0
  if (!this->checkSet(strKey)) return -1;
305
0
  if (this->setStore.find(strKey) == this->setStore.end()) return 0;
306
307
0
  return this->setStore[strKey].erase(std::string(item));
308
0
}
309
310
0
int Redis::smembers(lua_State *vm, char *setName) {
311
0
  stats.num_other++;
312
0
  std::string strKey(setName);
313
0
  if (!this->checkSet(strKey)) return -1;
314
0
  if (this->setStore.find(strKey) == this->setStore.end()) return 0;
315
316
0
  int k = 0;
317
0
  const auto &values = this->setStore[strKey];
318
0
  for (const auto &val : values) {
319
0
    lua_pushstring(vm, val.c_str());
320
0
    lua_rawseti(vm, -2, k + 1);
321
0
    ++k;
322
0
  }
323
324
0
  return 0;
325
0
}
326
327
4.66k
int Redis::smembers(const char *set_name, char ***members) {
328
4.66k
  std::string strKey(set_name);
329
4.66k
  if (this->setStore.find(strKey) == this->setStore.end()) {
330
4.66k
    *members = NULL;
331
4.66k
    return -1;
332
4.66k
  }
333
334
0
  int k = 0;
335
0
  const auto &values = this->setStore[strKey];
336
0
  if ((*members = (char **)malloc(values.size() * sizeof(char *))) != NULL)
337
0
    for (auto val : values) (*members)[k++] = strdup(val.c_str());
338
339
0
  return values.size();
340
4.66k
}
341
342
0
bool Redis::sismember(const char *set_name, const char *member) {
343
0
  stats.num_other++;
344
0
  std::string strKey(set_name);
345
0
  if (this->setStore.find(strKey) == this->setStore.end()) return false;
346
347
0
  return (this->setStore[strKey].find(std::string(member)) ==
348
0
    this->setStore[strKey].end());
349
0
}
350
351
int Redis::lpush(const char *queue_name, const char *msg, u_int queue_trim_size,
352
15
                 bool trace_errors /* = true */) {
353
15
  stats.num_lpush_rpush++;
354
15
  std::string strKey(queue_name);
355
15
  if (!this->checkList(strKey)) return -1;
356
357
15
  if (this->listStore.find(strKey) == this->listStore.end())
358
13
    this->listStore[strKey] = std::vector<std::string>();
359
360
15
  this->listStore[strKey].insert(this->listStore[strKey].begin(),
361
15
         std::string(msg));
362
363
15
  if (queue_trim_size > 0) {
364
3
    stats.num_trim++;
365
3
    if (this->ltrim(queue_name, -queue_trim_size, -1) == -1) return -1;
366
3
  }
367
368
15
  return this->listStore[strKey].size();
369
15
}
370
371
int Redis::rpush(const char *queue_name, const char *msg,
372
0
                 u_int queue_trim_size) {
373
0
  stats.num_lpush_rpush++;
374
0
  std::string strKey(queue_name);
375
0
  if (!this->checkList(strKey)) return -1;
376
377
0
  if (this->listStore.find(strKey) == this->listStore.end())
378
0
    this->listStore[strKey] = std::vector<std::string>();
379
380
0
  this->listStore[strKey].push_back(std::string(msg));
381
382
0
  if (queue_trim_size > 0) {
383
0
    stats.num_trim++;
384
0
    if (this->ltrim(queue_name, -queue_trim_size, -1) == -1) return -1;
385
0
  }
386
387
0
  return this->listStore[strKey].size();
388
0
}
389
390
0
int Redis::lindex(const char *queue_name, int idx, char *buf, u_int buf_len) {
391
0
  if (buf_len == 0) return -1;
392
0
  stats.num_other++;
393
0
  std::string strKey(queue_name);
394
0
  if (this->listStore.find(strKey) == this->listStore.end()) {
395
0
    buf[0] = 0;
396
0
    return -1;
397
0
  }
398
399
0
  const auto &list = this->listStore[strKey];
400
401
0
  if (idx < 0) idx += (int)list.size();
402
0
  if (idx < 0 || idx >= (int)list.size()) {
403
0
    buf[0] = 0;
404
0
    return -1;
405
0
  }
406
407
0
  snprintf(buf, buf_len, "%s", list[idx].c_str());
408
409
0
  return 0;
410
0
}
411
412
3
int Redis::ltrim(const char *queue_name, int start_idx, int end_idx) {
413
3
  stats.num_other++;
414
3
  std::string strKey(queue_name);
415
3
  if (this->listStore.find(strKey) == this->listStore.end()) return -1;
416
417
3
  auto &list = this->listStore[strKey];
418
3
  if (start_idx < 0) start_idx += list.size();
419
3
  if (end_idx < 0) end_idx += list.size();
420
3
  int k = 0;
421
9
  for (auto it = list.begin(); it != list.end(); ++k) {
422
6
    if (k < start_idx || k > end_idx)
423
0
      list.erase(it);
424
6
    else
425
6
      ++it;
426
6
  }
427
428
3
  return 0;
429
3
}
430
431
0
u_int Redis::hstrlen(const char *key, const char *value) {
432
0
  stats.num_other++;
433
0
  std::stringstream ss;
434
0
  ss << key << "@" << value;
435
0
  std::string strKey = ss.str();
436
0
  if (this->store.find(strKey) == this->store.end()) return 0;
437
438
0
  return this->store[strKey].size();
439
0
}
440
441
6
u_int Redis::len(const char *key) {
442
6
  std::string strKey(key);
443
6
  if (this->store.find(strKey) == this->store.end()) return 0;
444
445
0
  return this->store[strKey].size();
446
6
}
447
448
3
u_int Redis::llen(const char *queue_name) {
449
3
  stats.num_llen++;
450
3
  std::string strKey(queue_name);
451
3
  if (this->listStore.find(strKey) == this->listStore.end()) return 0;
452
453
2
  return this->listStore[strKey].size();
454
3
}
455
456
0
int Redis::lset(const char *queue_name, u_int32_t idx, const char *value) {
457
0
  return -1;
458
0
}
459
460
12
int Redis::lrem(const char *queue_name, const char *value) {
461
12
  stats.num_other++;
462
12
  std::string strKey(queue_name);
463
12
  if (this->listStore.find(strKey) == this->listStore.end()) return 0;
464
465
0
  for (auto it = this->listStore[strKey].begin();
466
0
       it != this->listStore[strKey].end();) {
467
0
    if (strncmp(it->c_str(), value, it->size()) == 0)
468
0
      this->listStore[strKey].erase(it);
469
0
    else
470
0
      ++it;
471
0
  }
472
0
  return 0;
473
12
}
474
475
int Redis::lrange(const char *list_name, char ***elements, int start_offset,
476
0
                  int end_offset) {
477
0
  stats.num_other++;
478
0
  std::string strKey(list_name);
479
0
  if (this->listStore.find(strKey) == this->listStore.end()) return 0;
480
481
0
  auto &list = this->listStore[strKey];
482
0
  if (start_offset < 0) start_offset += list.size();
483
0
  if (end_offset < 0) end_offset += list.size();
484
0
  int k = 0;
485
0
  vector<std::string> retList;
486
0
  for (auto it = list.begin(); it != list.end(); ++k, ++it) {
487
0
    if (k >= start_offset && k <= end_offset) retList.push_back(*it);
488
0
  }
489
490
0
  *elements = (char **)malloc(retList.size() * sizeof(char *));
491
0
  for (int i = 0; i < (int)retList.size(); ++i)
492
0
    (*elements)[i] = strdup(retList[i].c_str());
493
494
0
  return retList.size();
495
0
}
496
497
0
int Redis::lpop(const char *queue_name, char **buf) {
498
0
  *buf = NULL;
499
0
  stats.num_lpop_rpop++;
500
0
  std::string strKey(queue_name);
501
0
  if (this->listStore.find(strKey) == this->listStore.end()) {
502
0
    return -1;
503
0
  }
504
505
0
  if (this->listStore[strKey].size() == 0) {
506
0
    return -1;
507
0
  }
508
509
0
  *buf = (char *)strdup(this->listStore[strKey].front().c_str());
510
0
  if (!buf) {
511
0
    return -1;
512
0
  }
513
514
0
  this->listStore[strKey].erase(this->listStore[strKey].begin());
515
516
0
  return 0;
517
0
}
518
519
0
int Redis::rpop(const char *queue_name, char **buf) {
520
0
  *buf = NULL;
521
0
  stats.num_lpop_rpop++;
522
0
  std::string strKey(queue_name);
523
0
  if (this->listStore.find(strKey) == this->listStore.end()) {
524
0
    return -1;
525
0
  }
526
527
0
  if (this->listStore[strKey].size() == 0) {
528
0
    return -1;
529
0
  }
530
531
0
  *buf = (char *)strdup(this->listStore[strKey].back().c_str());
532
0
  if (!buf) {
533
0
    return -1;
534
0
  }
535
536
0
  this->listStore[strKey].pop_back();
537
538
0
  return 0;
539
0
}
540
541
0
int Redis::incr(const char *key, int amount) {
542
0
  std::string strKey(key);
543
0
  if (this->store.find(strKey) == this->store.end()) return 0;
544
545
0
  const auto &val = this->store[strKey];
546
0
  try {
547
0
    long l = std::stol(val);
548
0
    l += amount;
549
0
    std::stringstream ss;
550
0
    ss << l;
551
0
    this->store[strKey] = ss.str();
552
0
    return l;
553
0
  } catch (std::exception const &e) {
554
0
    return 0;
555
0
  }
556
0
}
557
558
0
int Redis::flushDb() {
559
0
  stats.num_other++;
560
0
  this->store.clear();
561
0
  return 0;
562
0
}
563
564
0
void Redis::flushCache() {}
565
566
0
void Redis::lua(lua_State *vm) {
567
0
  lua_newtable(vm);
568
569
0
  lua_push_uint64_table_entry(vm, "num_expire", stats.num_expire);
570
0
  lua_push_uint64_table_entry(vm, "num_get", stats.num_get);
571
0
  lua_push_uint64_table_entry(vm, "num_ttl", stats.num_ttl);
572
0
  lua_push_uint64_table_entry(vm, "num_del", stats.num_del);
573
0
  lua_push_uint64_table_entry(vm, "num_hget", stats.num_hget);
574
0
  lua_push_uint64_table_entry(vm, "num_hset", stats.num_hset);
575
0
  lua_push_uint64_table_entry(vm, "num_hdel", stats.num_hdel);
576
0
  lua_push_uint64_table_entry(vm, "num_set", stats.num_set);
577
0
  lua_push_uint64_table_entry(vm, "num_expire", stats.num_expire);
578
0
  lua_push_uint64_table_entry(vm, "num_keys", stats.num_keys);
579
0
  lua_push_uint64_table_entry(vm, "num_hkeys", stats.num_hkeys);
580
0
  lua_push_uint64_table_entry(vm, "num_hgetall", stats.num_hgetall);
581
0
  lua_push_uint64_table_entry(vm, "num_trim", stats.num_trim);
582
0
  lua_push_uint64_table_entry(vm, "num_reconnections",
583
0
            stats.num_reconnections);
584
0
  lua_push_uint64_table_entry(vm, "num_lpush_rpush", stats.num_lpush_rpush);
585
0
  lua_push_uint64_table_entry(vm, "num_lpop_rpop", stats.num_lpop_rpop);
586
0
  lua_push_uint64_table_entry(vm, "num_llen", stats.num_llen);
587
0
  lua_push_uint64_table_entry(vm, "num_strlen", stats.num_strlen);
588
0
  lua_push_uint64_table_entry(vm, "num_other", stats.num_other);
589
590
  /* Address resolution */
591
0
  lua_push_uint64_table_entry(vm, "num_resolver_saved_lookups",
592
0
            stats.num_saved_lookups);
593
0
  lua_push_uint64_table_entry(vm, "num_resolver_get_address",
594
0
            stats.num_get_address);
595
0
  lua_push_uint64_table_entry(vm, "num_resolver_set_address",
596
0
            stats.num_set_resolved_address);
597
0
}
598
599
0
char *Redis::dump(char *key) {
600
0
  stats.num_other++;
601
0
  char *ret = (char *)malloc(1);
602
0
  ret[0] = 0;
603
0
  return ret;
604
0
}
605
606
0
int Redis::restore(char *key, char *buf)  { return 0;     }
607
608
0
char* Redis::findAllWithAlloc(char* key)  { return(NULL); }
609
610
0
char* Redis::findBestWithAlloc(char* key) { return(NULL); }