Coverage Report

Created: 2025-11-16 06:59

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