Coverage Report

Created: 2023-11-19 06:42

/src/ntopng/src/Utils.cpp
Line
Count
Source (jump to first uncovered line)
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
#if defined(__OpenBSD__) || defined(__APPLE__) || defined(__FreeBSD__)
25
#include <net/if_dl.h>
26
#endif
27
28
#ifndef WIN32
29
#include <ifaddrs.h>
30
#endif
31
32
// #define TRACE_CEPABILITIES
33
34
static const char *hex_chars = "0123456789ABCDEF";
35
36
2
static map<string, int> initTcpStatesStr2State() {
37
2
  map<string, int> states_map;
38
39
2
  states_map["ESTABLISHED"] = TCP_ESTABLISHED;
40
2
  states_map["SYN-SENT"] = TCP_SYN_SENT;
41
2
  states_map["SYN-RECV"] = TCP_SYN_RECV;
42
2
  states_map["FIN-WAIT-1"] = TCP_FIN_WAIT1;
43
2
  states_map["FIN-WAIT-2"] = TCP_FIN_WAIT2;
44
2
  states_map["TIME-WAIT"] = TCP_TIME_WAIT;
45
2
  states_map["CLOSE"] = TCP_CLOSE;
46
2
  states_map["CLOSE-WAIT"] = TCP_CLOSE_WAIT;
47
2
  states_map["LAST-ACK"] = TCP_LAST_ACK;
48
2
  states_map["LISTEN"] = TCP_LISTEN;
49
2
  states_map["CLOSING"] = TCP_CLOSING;
50
51
2
  return states_map;
52
2
}
53
54
2
static map<string, eBPFEventType> initeBPFEventTypeStr2Type() {
55
2
  map<string, eBPFEventType> events_map;
56
57
  /* TCP EVENTS */
58
2
  events_map["ACCEPT"] = ebpf_event_type_tcp_accept;
59
2
  events_map["CONNECT"] = ebpf_event_type_tcp_connect;
60
2
  events_map["CONNECT_FAILED"] = ebpf_event_type_tcp_connect_failed;
61
2
  events_map["CLOSE"] = ebpf_event_type_tcp_close;
62
2
  events_map["RETRANSMIT"] = epbf_event_type_tcp_retransmit;
63
64
  /* UDP EVENTS */
65
2
  events_map["SEND"] = ebpf_event_type_udp_send;
66
2
  events_map["RECV"] = ebpf_event_type_udp_recv;
67
68
2
  return events_map;
69
2
};
70
71
static map<int, string> initTcpStates2StatesStr(
72
2
    const map<string, int> &tcp_states_str_to_state) {
73
2
  map<int, string> states_map;
74
2
  map<string, int>::const_iterator it;
75
76
2
  for (it = tcp_states_str_to_state.begin();
77
24
       it != tcp_states_str_to_state.end(); it++) {
78
22
    states_map[it->second] = it->first;
79
22
  }
80
81
2
  return states_map;
82
2
}
83
84
static map<eBPFEventType, string> initeBPFEventType2TypeStr(
85
2
    const map<string, eBPFEventType> &tcp_states_str_to_state) {
86
2
  map<eBPFEventType, string> events_map;
87
2
  map<string, eBPFEventType>::const_iterator it;
88
89
2
  for (it = tcp_states_str_to_state.begin();
90
16
       it != tcp_states_str_to_state.end(); it++) {
91
14
    events_map[it->second] = it->first;
92
14
  }
93
94
2
  return events_map;
95
2
};
96
97
static const map<string, int> tcp_state_str_2_state = initTcpStatesStr2State();
98
static const map<int, string> tcp_state_2_state_str =
99
    initTcpStates2StatesStr(tcp_state_str_2_state);
100
static const map<string, eBPFEventType> ebpf_event_str_2_event =
101
    initeBPFEventTypeStr2Type();
102
static const map<eBPFEventType, string> ebpf_event_2_event_str =
103
    initeBPFEventType2TypeStr(ebpf_event_str_2_event);
104
105
// A simple struct for strings.
106
typedef struct {
107
  char *s;
108
  size_t l;
109
} String;
110
111
typedef struct {
112
  u_int8_t header_over;
113
  char outbuf[3 * 65536];
114
  u_int num_bytes;
115
  lua_State *vm;
116
  bool return_content;
117
} DownloadState;
118
119
#ifdef HAVE_LIBCAP
120
/*
121
   The include below can be found in libcap-dev
122
123
   sudo apt-get install libcap-dev
124
*/
125
#include <sys/capability.h>
126
#include <sys/prctl.h>
127
128
static cap_value_t cap_values[] = {
129
    CAP_DAC_OVERRIDE, /* Bypass file read, write, and execute permission checks
130
                       */
131
    CAP_NET_ADMIN,    /* Perform various network-related operations */
132
    CAP_NET_RAW       /* Use RAW and PACKET sockets */
133
};
134
135
int num_cap = sizeof(cap_values) / sizeof(cap_value_t);
136
#endif
137
138
static size_t curl_writefunc_to_lua(char *buffer, size_t size, size_t nitems,
139
                                    void *userp);
140
static size_t curl_hdf(char *buffer, size_t size, size_t nitems, void *userp);
141
142
/* ****************************************************** */
143
144
char *Utils::jsonLabel(int label, const char *label_str, char *buf,
145
0
                       u_int buf_len) {
146
0
  if (ntop->getPrefs()->json_labels_as_strings()) {
147
0
    snprintf(buf, buf_len, "%s", label_str);
148
0
  } else
149
0
    snprintf(buf, buf_len, "%d", label);
150
151
0
  return (buf);
152
0
}
153
154
/* ****************************************************** */
155
156
0
char *Utils::formatTraffic(float numBits, bool bits, char *buf, u_int buf_len) {
157
0
  char unit;
158
159
0
  if (bits)
160
0
    unit = 'b';
161
0
  else
162
0
    unit = 'B';
163
164
0
  if (numBits < 1024) {
165
0
    snprintf(buf, buf_len, "%lu %c", (unsigned long)numBits, unit);
166
0
  } else if (numBits < 1048576) {
167
0
    snprintf(buf, buf_len, "%.2f K%c", (float)(numBits) / 1024, unit);
168
0
  } else {
169
0
    float tmpMBits = ((float)numBits) / 1048576;
170
171
0
    if (tmpMBits < 1024) {
172
0
      snprintf(buf, buf_len, "%.2f M%c", tmpMBits, unit);
173
0
    } else {
174
0
      tmpMBits /= 1024;
175
176
0
      if (tmpMBits < 1024) {
177
0
        snprintf(buf, buf_len, "%.2f G%c", tmpMBits, unit);
178
0
      } else {
179
0
        snprintf(buf, buf_len, "%.2f T%c", (float)(tmpMBits) / 1024, unit);
180
0
      }
181
0
    }
182
0
  }
183
184
0
  return (buf);
185
0
}
186
187
/* ****************************************************** */
188
189
0
char *Utils::formatPackets(float numPkts, char *buf, u_int buf_len) {
190
0
  if (numPkts < 1000) {
191
0
    snprintf(buf, buf_len, "%.2f", numPkts);
192
0
  } else if (numPkts < 1000000) {
193
0
    snprintf(buf, buf_len, "%.2f K", numPkts / (float)1000);
194
0
  } else {
195
0
    numPkts /= 1000000;
196
0
    snprintf(buf, buf_len, "%.2f M", numPkts);
197
0
  }
198
199
0
  return (buf);
200
0
}
201
202
/* ****************************************************** */
203
204
0
char *Utils::l4proto2name(u_int8_t proto) {
205
0
  static char proto_string[8];
206
207
  /* NOTE: keep in sync with /lua/pro/db_explorer_data.lua */
208
209
0
  switch (proto) {
210
0
    case 0:
211
0
      return ((char *)"IP");
212
0
    case 1:
213
0
      return ((char *)"ICMP");
214
0
    case 2:
215
0
      return ((char *)"IGMP");
216
0
    case 6:
217
0
      return ((char *)"TCP");
218
0
    case 17:
219
0
      return ((char *)"UDP");
220
0
    case 41:
221
0
      return ((char *)"IPv6");
222
0
    case 46:
223
0
      return ((char *)"RSVP");
224
0
    case 47:
225
0
      return ((char *)"GRE");
226
0
    case 50:
227
0
      return ((char *)"ESP");
228
0
    case 51:
229
0
      return ((char *)"AH");
230
0
    case 58:
231
0
      return ((char *)"IPv6-ICMP");
232
0
    case 88:
233
0
      return ((char *)"EIGRP");
234
0
    case 89:
235
0
      return ((char *)"OSPF");
236
0
    case 103:
237
0
      return ((char *)"PIM");
238
0
    case 112:
239
0
      return ((char *)"VRRP");
240
0
    case 139:
241
0
      return ((char *)"HIP");
242
243
0
    default:
244
0
      snprintf(proto_string, sizeof(proto_string), "%u", proto);
245
0
      return (proto_string);
246
0
  }
247
0
}
248
249
/* ****************************************************** */
250
251
0
const char *Utils::edition2name(NtopngEdition ntopng_edition) {
252
0
  switch (ntopng_edition) {
253
0
    case ntopng_edition_community:
254
0
      return "community";
255
0
    case ntopng_edition_pro:
256
0
      return "pro";
257
0
    case ntopng_edition_enterprise_m:
258
0
      return "enterprise_m";
259
0
    case ntopng_edition_enterprise_l:
260
0
      return "enterprise_l";
261
0
    default:
262
0
      return "unknown";
263
0
  }
264
0
}
265
266
/* ****************************************************** */
267
268
0
u_int8_t Utils::l4name2proto(const char *name) {
269
0
  if (strcmp(name, "IP") == 0)
270
0
    return 0;
271
0
  else if (strcmp(name, "ICMP") == 0)
272
0
    return 1;
273
0
  else if (strcmp(name, "IGMP") == 0)
274
0
    return 2;
275
0
  else if (strcmp(name, "TCP") == 0)
276
0
    return 6;
277
0
  else if (strcmp(name, "UDP") == 0)
278
0
    return 17;
279
0
  else if (strcmp(name, "IPv6") == 0)
280
0
    return 41;
281
0
  else if (strcmp(name, "RSVP") == 0)
282
0
    return 46;
283
0
  else if (strcmp(name, "GRE") == 0)
284
0
    return 47;
285
0
  else if (strcmp(name, "ESP") == 0)
286
0
    return 50;
287
0
  else if (strcmp(name, "AH") == 0)
288
0
    return 51;
289
0
  else if (strcmp(name, "IPv6-ICMP") == 0)
290
0
    return 58;
291
0
  else if (strcmp(name, "OSPF") == 0)
292
0
    return 89;
293
0
  else if (strcmp(name, "PIM") == 0)
294
0
    return 103;
295
0
  else if (strcmp(name, "VRRP") == 0)
296
0
    return 112;
297
0
  else if (strcmp(name, "HIP") == 0)
298
0
    return 139;
299
0
  else
300
0
    return 0;
301
0
}
302
303
/* ****************************************************** */
304
305
0
u_int8_t Utils::queryname2type(const char *name) {
306
0
  if (strcmp(name, "A") == 0)
307
0
    return 1;
308
0
  else if (strcmp(name, "NS") == 0)
309
0
    return 2;
310
0
  else if (strcmp(name, "MD") == 0)
311
0
    return 3;
312
0
  else if (strcmp(name, "MF") == 0)
313
0
    return 4;
314
0
  else if (strcmp(name, "CNAME") == 0)
315
0
    return 5;
316
0
  else if (strcmp(name, "SOA") == 0)
317
0
    return 6;
318
0
  else if (strcmp(name, "MB") == 0)
319
0
    return 7;
320
0
  else if (strcmp(name, "MG") == 0)
321
0
    return 8;
322
0
  else if (strcmp(name, "MR") == 0)
323
0
    return 9;
324
0
  else if (strcmp(name, "NULL") == 0)
325
0
    return 10;
326
0
  else if (strcmp(name, "WKS") == 0)
327
0
    return 11;
328
0
  else if (strcmp(name, "PTR") == 0)
329
0
    return 12;
330
0
  else if (strcmp(name, "HINFO") == 0)
331
0
    return 13;
332
0
  else if (strcmp(name, "MINFO") == 0)
333
0
    return 14;
334
0
  else if (strcmp(name, "MX") == 0)
335
0
    return 15;
336
0
  else if (strcmp(name, "TXT") == 0)
337
0
    return 16;
338
0
  else if (strcmp(name, "AAAA") == 0)
339
0
    return 28;
340
0
  else if (strcmp(name, "A6") == 0)
341
0
    return 38;
342
0
  else if (strcmp(name, "SPF") == 0)
343
0
    return 99;
344
0
  else if (strcmp(name, "AXFR") == 0)
345
0
    return 252;
346
0
  else if (strcmp(name, "MAILB") == 0)
347
0
    return 253;
348
0
  else if (strcmp(name, "MAILA") == 0)
349
0
    return 254;
350
0
  else if (strcmp(name, "ANY") == 0)
351
0
    return 255;
352
0
  else
353
0
    return 0;
354
0
}
355
356
/* ****************************************************** */
357
358
6.26k
bool Utils::isIPAddress(const char *ip) {
359
6.26k
  struct in_addr addr4;
360
6.26k
  struct in6_addr addr6;
361
362
6.26k
  if ((ip == NULL) || (ip[0] == '\0')) return (false);
363
364
2.52k
  if (strchr(ip, ':') != NULL) { /* IPv6 */
365
46
    if (inet_pton(AF_INET6, ip, &addr6) == 1) return (true);
366
2.47k
  } else {
367
2.47k
    if (inet_pton(AF_INET, ip, &addr4) == 1) return (true);
368
2.47k
  }
369
370
2.46k
  return (false);
371
2.52k
}
372
373
/* ****************************************************** */
374
375
#ifdef PROFILING
376
0
u_int64_t Utils::getTimeNsec() {
377
0
  u_int64_t nsec = 0;
378
0
#ifdef __linux__
379
0
  struct timespec t;
380
381
0
  if (clock_gettime(CLOCK_REALTIME, &t) == 0)
382
0
    nsec = (u_int64_t)((u_int64_t)t.tv_sec * 1000000000) + t.tv_nsec;
383
0
#endif
384
385
0
  return nsec;
386
0
}
387
#endif
388
389
/* ****************************************************** */
390
391
#ifdef __linux__
392
393
0
int Utils::setAffinityMask(char *cores_list, cpu_set_t *mask) {
394
0
  int ret = 0;
395
#ifdef HAVE_LIBCAP
396
  char *core_id_s, *tmp = NULL;
397
  u_int num_cores = ntop->getNumCPUs();
398
399
  CPU_ZERO(mask);
400
401
  if (cores_list == NULL) return 0;
402
403
  if (num_cores <= 1) return 0;
404
405
  core_id_s = strtok_r(cores_list, ",", &tmp);
406
407
  while (core_id_s) {
408
    long core_id = atoi(core_id_s);
409
    u_long core = core_id % num_cores;
410
411
    CPU_SET(core, mask);
412
413
    core_id_s = strtok_r(NULL, ",", &tmp);
414
  }
415
#endif
416
417
0
  return ret;
418
0
}
419
#endif
420
421
/* ****************************************************** */
422
423
#ifdef __linux__
424
0
int Utils::setThreadAffinityWithMask(pthread_t thread, cpu_set_t *mask) {
425
0
  int ret = -1;
426
427
0
  if (mask == NULL || CPU_COUNT(mask) == 0) return (0);
428
429
#ifdef HAVE_LIBCAP
430
  ret = pthread_setaffinity_np(thread, sizeof(cpu_set_t), mask);
431
#endif
432
433
0
  return (ret);
434
0
}
435
#endif
436
437
/* ****************************************************** */
438
439
0
int Utils::setThreadAffinity(pthread_t thread, int core_id) {
440
0
#ifdef __linux__
441
0
  if (core_id < 0)
442
0
    return (0);
443
0
  else {
444
0
    int ret = -1;
445
#ifdef HAVE_LIBCAP
446
    u_int num_cores = ntop->getNumCPUs();
447
    u_long core = core_id % num_cores;
448
    cpu_set_t cpu_set;
449
450
    if (num_cores > 1) {
451
      CPU_ZERO(&cpu_set);
452
      CPU_SET(core, &cpu_set);
453
      ret = setThreadAffinityWithMask(thread, &cpu_set);
454
    }
455
#endif
456
457
0
    return (ret);
458
0
  }
459
#else
460
  return (0);
461
#endif
462
0
}
463
464
/* ****************************************************** */
465
466
0
void Utils::setThreadName(const char *name) {
467
0
#if defined(__APPLE__) || defined(__linux__)
468
  // Mac OS X: must be set from within the thread (can't specify thread ID)
469
0
  char buf[16];  // NOTE: on linux there is a 16 char limit
470
0
  int rc;
471
0
  char *bname = NULL;
472
473
0
  if (Utils::file_exists(name)) {
474
0
    bname = strrchr((char *)name, '/');
475
0
    if (bname) bname++;
476
0
  }
477
478
0
  snprintf(buf, sizeof(buf), "%s", bname ? bname : name);
479
480
#if defined(__APPLE__)
481
  if ((rc = pthread_setname_np(buf)))
482
#else
483
0
  if ((rc = pthread_setname_np(pthread_self(), buf)))
484
0
#endif
485
0
    ntop->getTrace()->traceEvent(TRACE_WARNING,
486
0
                                 "Unable to set pthread name %s: %d", buf, rc);
487
0
#endif
488
0
}
489
490
/* ****************************************************** */
491
492
0
char *Utils::trim(char *s) {
493
0
  char *end;
494
495
0
  while (isspace(s[0]) || (s[0] == '"') || (s[0] == '\'')) s++;
496
0
  if (s[0] == 0) return s;
497
498
0
  end = &s[strlen(s) - 1];
499
0
  while (end > s && (isspace(end[0]) || (end[0] == '"') || (end[0] == '\'')))
500
0
    end--;
501
0
  end[1] = 0;
502
503
0
  return s;
504
0
}
505
506
/* ****************************************************** */
507
508
433
u_int32_t Utils::hashString(const char *key, u_int32_t len) {
509
433
  if (!key) return 0;
510
511
433
  u_int32_t hash = 0;
512
513
433
  if (len == 0) len = (u_int32_t)strlen(key);
514
515
15.1k
  for (u_int32_t i = 0; i < len; i++) hash += ((u_int32_t)key[i]) * i;
516
517
433
  return hash;
518
433
}
519
520
/* ****************************************************** */
521
522
907
float Utils::timeval2ms(const struct timeval *tv) {
523
907
  return ((float)tv->tv_sec * 1000 + (float)tv->tv_usec / 1000);
524
907
}
525
526
/* ****************************************************** */
527
528
1.73k
u_int32_t Utils::timeval2usec(const struct timeval *tv) {
529
1.73k
  return (tv->tv_sec * 1000000 + tv->tv_usec);
530
1.73k
}
531
532
/* ****************************************************** */
533
534
u_int32_t Utils::usecTimevalDiff(const struct timeval *end,
535
0
                                 const struct timeval *begin) {
536
0
  if ((end->tv_sec == 0) && (end->tv_usec == 0))
537
0
    return (0);
538
0
  else {
539
0
    struct timeval res;
540
541
0
    res.tv_sec = end->tv_sec - begin->tv_sec;
542
0
    if (begin->tv_usec > end->tv_usec) {
543
0
      res.tv_usec = end->tv_usec + 1000000 - begin->tv_usec;
544
0
      res.tv_sec--;
545
0
    } else
546
0
      res.tv_usec = end->tv_usec - begin->tv_usec;
547
548
0
    return ((res.tv_sec * 1000000) + (res.tv_usec));
549
0
  }
550
0
}
551
552
/* ****************************************************** */
553
554
float Utils::msTimevalDiff(const struct timeval *end,
555
233k
                           const struct timeval *begin) {
556
233k
  if ((end->tv_sec == 0) && (end->tv_usec == 0))
557
380
    return (0);
558
232k
  else {
559
232k
    struct timeval res;
560
561
232k
    res.tv_sec = end->tv_sec - begin->tv_sec;
562
232k
    if (begin->tv_usec > end->tv_usec) {
563
26.7k
      res.tv_usec = end->tv_usec + 1000000 - begin->tv_usec;
564
26.7k
      res.tv_sec--;
565
26.7k
    } else
566
206k
      res.tv_usec = end->tv_usec - begin->tv_usec;
567
568
232k
    return (((float)res.tv_sec * 1000) + ((float)res.tv_usec / (float)1000));
569
232k
  }
570
233k
}
571
572
/* ****************************************************** */
573
574
/* Converts a ISO 8601 timestamp (exported by Suricata) to epoch.
575
 * Example: 2019-04-02T19:29:42.346861+0200 */
576
0
time_t Utils::str2epoch(const char *str) {
577
0
  struct tm tm;
578
0
  time_t t;
579
0
  const char *format = "%FT%T%Z";
580
581
0
  memset(&tm, 0, sizeof(tm));
582
583
0
  if (strptime(str, format, &tm) == NULL) return 0;
584
585
0
  t = mktime(&tm) + (3600 * tm.tm_isdst);
586
587
0
#ifndef WIN32
588
0
  t -= tm.tm_gmtoff;
589
0
#endif
590
591
0
  if (t == -1) return 0;
592
593
0
  return t;
594
0
}
595
596
/* ****************************************************** */
597
598
0
bool Utils::file_exists(const char *path) {
599
0
  std::ifstream infile(path);
600
601
  /*  ntop->getTrace()->traceEvent(TRACE_WARNING, "%s(): %s", __FUNCTION__,
602
   * path); */
603
0
  bool ret = infile.good();
604
0
  infile.close();
605
0
  return ret;
606
0
}
607
608
/* ****************************************************** */
609
610
2
bool Utils::dir_exists(const char *path) {
611
2
  struct stat buf;
612
613
2
  return !((stat(path, &buf) != 0) || (!S_ISDIR(buf.st_mode)));
614
2
}
615
616
/* ****************************************************** */
617
618
size_t Utils::file_write(const char *path, const char *content,
619
0
                         size_t content_len) {
620
0
  size_t ret = 0;
621
0
  FILE *fd = fopen(path, "wb");
622
623
0
  if (fd == NULL) {
624
0
    ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to write file %s",
625
0
                                 path);
626
0
  } else {
627
0
#ifndef WIN32
628
0
    chmod(path, CONST_DEFAULT_FILE_MODE);
629
0
#endif
630
631
0
    ret = fwrite(content, content_len, 1, fd);
632
0
    fclose(fd);
633
0
  }
634
635
0
  return ret;
636
0
}
637
638
/* ****************************************************** */
639
640
0
size_t Utils::file_read(const char *path, char **content) {
641
0
  size_t ret = 0;
642
0
  char *buffer = NULL;
643
0
  u_int64_t length;
644
0
  FILE *f = fopen(path, "rb");
645
646
0
  if (f) {
647
0
    fseek(f, 0, SEEK_END);
648
0
    length = ftell(f);
649
0
    fseek(f, 0, SEEK_SET);
650
651
0
    buffer = (char *)malloc(length);
652
0
    if (buffer) ret = fread(buffer, 1, length, f);
653
654
0
    fclose(f);
655
656
0
    if (buffer) {
657
0
      if (content && ret)
658
0
        *content = buffer;
659
0
      else
660
0
        free(buffer);
661
0
    }
662
0
  }
663
664
0
  return ret;
665
0
}
666
667
/* ****************************************************** */
668
669
0
int Utils::remove_recursively(const char *path) {
670
0
  DIR *d = opendir(path);
671
0
  size_t path_len = strlen(path);
672
0
  int r = -1;
673
0
  size_t len;
674
0
  char *buf;
675
676
0
  if (d) {
677
0
    struct dirent *p;
678
679
0
    r = 0;
680
681
0
    while ((r == 0) && (p = readdir(d))) {
682
      /* Skip the names "." and ".." as we don't want to recurse on them. */
683
0
      if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) continue;
684
685
0
      len = path_len + strlen(p->d_name) + 2;
686
0
      buf = (char *)malloc(len);
687
688
0
      if (buf) {
689
0
        struct stat statbuf;
690
691
0
        snprintf(buf, len, "%s/%s", path, p->d_name);
692
693
0
        if (stat(buf, &statbuf) == 0) {
694
0
          if (S_ISDIR(statbuf.st_mode))
695
0
            r = remove_recursively(buf);
696
0
          else
697
0
            r = unlink(buf);
698
0
        }
699
700
0
        free(buf);
701
0
      }
702
0
    }
703
704
0
    closedir(d);
705
0
  }
706
707
0
  if (r == 0) r = rmdir(path);
708
709
0
  return r;
710
0
}
711
712
/* ****************************************************** */
713
714
4
bool Utils::mkdir_tree(char *const path) {
715
4
  int rc;
716
4
  struct stat s;
717
718
4
  ntop->fixPath(path);
719
720
4
  if (stat(path, &s) != 0) {
721
    /* Start at 1 to skip the root */
722
121
    for (int i = 1; path[i] != '\0'; i++)
723
121
      if (path[i] == CONST_PATH_SEP) {
724
#ifdef WIN32
725
        /* Do not create devices directory */
726
        if ((i > 1) && (path[i - 1] == ':')) continue;
727
#endif
728
729
        /*
730
         * If we are already handling the final portion
731
         * of a path, e.g. because the path has a trailing
732
         * CONST_PATH_SEP, do not create the final
733
         * directory: it will be created later.
734
         */
735
12
        if (path[i + 1] == '\0') break;
736
737
10
        path[i] = '\0';
738
10
        rc = Utils::mkdir(path, CONST_DEFAULT_DIR_MODE);
739
740
10
        path[i] = CONST_PATH_SEP;
741
10
      }
742
743
2
    rc = Utils::mkdir(path, CONST_DEFAULT_DIR_MODE);
744
745
2
    return (((rc == 0) || (errno == EEXIST /* Already existing */)) ? true
746
2
                                                                    : false);
747
2
  } else
748
2
    return (true); /* Already existing */
749
4
}
750
751
/* **************************************************** */
752
753
12
int Utils::mkdir(const char *path, mode_t mode) {
754
#ifdef WIN32
755
  return (_mkdir(path));
756
#else
757
12
  int rc = ::mkdir(path, mode);
758
759
12
  if (rc == -1) {
760
9
    if (errno != EEXIST)
761
0
      ntop->getTrace()->traceEvent(TRACE_WARNING, "mkdir(%s) failed [%d/%s]",
762
0
                                   path, errno, strerror(errno));
763
9
  } else {
764
3
    if (chmod(path, mode) == -1) /* Ubuntu 18 */
765
0
      ntop->getTrace()->traceEvent(TRACE_WARNING, "chmod(%s) failed [%d/%s]",
766
0
                                   path, errno, strerror(errno));
767
3
  }
768
769
12
  return (rc);
770
12
#endif
771
12
}
772
773
/* **************************************************** */
774
775
0
const char *Utils::trend2str(ValueTrend t) {
776
0
  switch (t) {
777
0
    case trend_up:
778
0
      return ("Up");
779
0
      break;
780
781
0
    case trend_down:
782
0
      return ("Down");
783
0
      break;
784
785
0
    case trend_stable:
786
0
      return ("Stable");
787
0
      break;
788
789
0
    default:
790
0
    case trend_unknown:
791
0
      return ("Unknown");
792
0
      break;
793
0
  }
794
0
}
795
796
/* **************************************************** */
797
798
0
int Utils::dropPrivileges() {
799
0
#ifndef WIN32
800
0
  struct passwd *pw = NULL;
801
0
  const char *username;
802
0
  int rv;
803
804
0
  if (getgid() && getuid()) {
805
0
    ntop->getTrace()->traceEvent(
806
0
        TRACE_NORMAL, "Privileges are not dropped as we're not superuser");
807
0
    return -1;
808
0
  }
809
810
0
  if (Utils::retainWriteCapabilities() != 0) {
811
#ifdef HAVE_LIBCAP
812
    ntop->getTrace()->traceEvent(
813
        TRACE_WARNING,
814
        "Unable to retain privileges for privileged file writing");
815
#endif
816
0
  }
817
818
0
  username = ntop->getPrefs()->get_user();
819
0
  pw = getpwnam(username);
820
821
0
  if (pw == NULL) {
822
    /* if the user (e.g. 'ntopng') does not exists, falls back to 'nobody' */
823
0
    username = CONST_OLD_DEFAULT_NTOP_USER;
824
0
    pw = getpwnam(username);
825
0
  }
826
827
0
  if (pw != NULL) {
828
    /* Change the working dir ownership */
829
0
    rv = chown(ntop->get_working_dir(), pw->pw_uid, pw->pw_gid);
830
0
    if (rv != 0)
831
0
      ntop->getTrace()->traceEvent(TRACE_ERROR,
832
0
                                   "Unable to change working dir '%s' owner",
833
0
                                   ntop->get_working_dir());
834
835
0
    if (ntop->getPrefs()->get_pid_path() != NULL) {
836
      /* Change PID file ownership to be able to delete it on shutdown */
837
0
      rv = chown(ntop->getPrefs()->get_pid_path(), pw->pw_uid, pw->pw_gid);
838
0
      if (rv != 0)
839
0
        ntop->getTrace()->traceEvent(TRACE_ERROR,
840
0
                                     "Unable to change owner to PID in file %s",
841
0
                                     ntop->getPrefs()->get_pid_path());
842
0
    }
843
844
    /* Drop privileges */
845
    /* Dear programmer, initgroups() is necessary as there may be extra groups
846
       for the user that we are going to drop privileges to that are not yet
847
       visible. This can happen for newely created groups, or when a user has
848
       been added to a new group.
849
       Don't remove it or you will waste hours of life.
850
     */
851
0
    if ((initgroups(pw->pw_name, pw->pw_gid) != 0) ||
852
0
        (setgid(pw->pw_gid) != 0) || (setuid(pw->pw_uid) != 0)) {
853
0
      ntop->getTrace()->traceEvent(
854
0
          TRACE_WARNING, "Unable to drop privileges [%s]", strerror(errno));
855
0
      return -1;
856
0
    }
857
858
0
    if (ntop) ntop->setDroppedPrivileges();
859
860
0
    ntop->getTrace()->traceEvent(TRACE_NORMAL, "User changed to %s", username);
861
0
#ifndef WIN32
862
0
    ntop->getTrace()->traceEvent(TRACE_INFO, "Umask: %#o", umask(0077));
863
0
#endif
864
0
  } else {
865
0
    ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to locate user %s",
866
0
                                 username);
867
0
    return -1;
868
0
  }
869
  // umask(0);
870
0
#endif
871
0
  return 0;
872
0
}
873
874
/* **************************************************** */
875
876
/* http://www.adp-gmbh.ch/cpp/common/base64.html */
877
static const std::string base64_chars =
878
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
879
    "abcdefghijklmnopqrstuvwxyz"
880
    "0123456789+/";
881
882
0
static inline bool is_base64(unsigned char c) {
883
0
  return (isalnum(c) || (c == '+') || (c == '/'));
884
0
}
885
886
/* **************************************************** */
887
888
char *Utils::base64_encode(unsigned char const *bytes_to_encode,
889
0
                           ssize_t in_len) {
890
0
  char *res = NULL;
891
0
  ssize_t res_len = 0;
892
0
  std::string ret;
893
0
  int i = 0;
894
0
  unsigned char char_array_3[3];
895
0
  unsigned char char_array_4[4];
896
897
0
  while (in_len--) {
898
0
    char_array_3[i++] = *(bytes_to_encode++);
899
0
    if (i == 3) {
900
0
      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
901
0
      char_array_4[1] =
902
0
          ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
903
0
      char_array_4[2] =
904
0
          ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
905
0
      char_array_4[3] = char_array_3[2] & 0x3f;
906
907
0
      for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]];
908
0
      i = 0;
909
0
    }
910
0
  }
911
912
0
  if (i) {
913
0
    for (int j = i; j < 3; j++) char_array_3[j] = '\0';
914
915
0
    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
916
0
    char_array_4[1] =
917
0
        ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
918
0
    char_array_4[2] =
919
0
        ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
920
0
    char_array_4[3] = char_array_3[2] & 0x3f;
921
922
0
    for (int j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]];
923
924
0
    while ((i++ < 3)) ret += '=';
925
0
  }
926
927
0
  if ((res = (char *)calloc(sizeof(char), ret.size() + 1))) {
928
0
    res_len = ret.copy(res, ret.size());
929
0
    res[res_len] = '\0';
930
0
  }
931
932
0
  return res;
933
0
}
934
935
/* **************************************************** */
936
937
0
std::string Utils::base64_decode(std::string const &encoded_string) {
938
0
  int in_len = encoded_string.size();
939
0
  int i = 0, in_ = 0;
940
0
  unsigned char char_array_4[4], char_array_3[3];
941
0
  std::string ret;
942
943
0
  while (in_len-- && (encoded_string[in_] != '=') &&
944
0
         is_base64(encoded_string[in_])) {
945
0
    char_array_4[i++] = encoded_string[in_];
946
0
    in_++;
947
948
0
    if (i == 4) {
949
0
      for (i = 0; i < 4; i++)
950
0
        char_array_4[i] = base64_chars.find(char_array_4[i]);
951
952
0
      char_array_3[0] =
953
0
          (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
954
0
      char_array_3[1] =
955
0
          ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
956
0
      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
957
958
0
      for (i = 0; (i < 3); i++) ret += char_array_3[i];
959
0
      i = 0;
960
0
    }
961
0
  }
962
963
0
  if (i) {
964
0
    int j;
965
966
0
    for (j = i; j < 4; j++) char_array_4[j] = 0;
967
968
0
    for (j = 0; j < 4; j++)
969
0
      char_array_4[j] = base64_chars.find(char_array_4[j]);
970
971
0
    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
972
0
    char_array_3[1] =
973
0
        ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
974
0
    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
975
976
0
    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
977
0
  }
978
979
0
  return ret;
980
0
}
981
982
/* *************************************** */
983
984
0
double Utils::pearsonValueCorrelation(activity_bitmap *x, activity_bitmap *y) {
985
0
  double ex = 0, ey = 0, sxx = 0, syy = 0, sxy = 0, tiny_value = 1e-2;
986
987
0
  for (size_t i = 0; i < NUM_MINUTES_PER_DAY; i++) {
988
    /* Find the means */
989
0
    ex += x->counter[i], ey += y->counter[i];
990
0
  }
991
992
0
  ex /= NUM_MINUTES_PER_DAY, ey /= NUM_MINUTES_PER_DAY;
993
994
0
  for (size_t i = 0; i < NUM_MINUTES_PER_DAY; i++) {
995
    /* Compute the correlation coefficient */
996
0
    double xt = x->counter[i] - ex, yt = y->counter[i] - ey;
997
998
0
    sxx += xt * xt, syy += yt * yt, sxy += xt * yt;
999
0
  }
1000
1001
0
  return (sxy / (sqrt(sxx * syy) + tiny_value));
1002
0
}
1003
1004
/* *************************************** */
1005
/* XXX: it assumes that the vectors are bitmaps */
1006
0
double Utils::JaccardSimilarity(activity_bitmap *x, activity_bitmap *y) {
1007
0
  size_t inter_card = 0, union_card = 0;
1008
1009
0
  for (size_t i = 0; i < NUM_MINUTES_PER_DAY; i++) {
1010
0
    union_card += x->counter[i] | y->counter[i];
1011
0
    inter_card += x->counter[i] & y->counter[i];
1012
0
  }
1013
1014
0
  if (union_card == 0) return (1e-2);
1015
1016
0
  return ((double)inter_card / union_card);
1017
0
}
1018
1019
/* *************************************** */
1020
1021
#ifdef WIN32
1022
extern "C" {
1023
const char *strcasestr(const char *haystack, const char *needle) {
1024
  int i = -1;
1025
1026
  while (haystack[++i] != '\0') {
1027
    if (tolower(haystack[i]) == tolower(needle[0])) {
1028
      int j = i, k = 0, match = 0;
1029
      while (tolower(haystack[++j]) == tolower(needle[++k])) {
1030
        match = 1;
1031
        // Catch case when they match at the end
1032
        // printf("j:%d, k:%d\n",j,k);
1033
        if (haystack[j] == '\0' && needle[k] == '\0') {
1034
          // printf("Mj:%d, k:%d\n",j,k);
1035
          return &haystack[i];
1036
        }
1037
      }
1038
      // Catch normal case
1039
      if (match && needle[k] == '\0') {
1040
        // printf("Norm j:%d, k:%d\n",j,k);
1041
        return &haystack[i];
1042
      }
1043
    }
1044
  }
1045
1046
  return NULL;
1047
}
1048
};
1049
#endif
1050
1051
/* **************************************************** */
1052
1053
4
int Utils::ifname2id(const char *name) {
1054
4
  char rsp[MAX_INTERFACE_NAME_LEN], ifidx[8];
1055
1056
4
  if (name && !strcmp(name, SYSTEM_INTERFACE_NAME)) return SYSTEM_INTERFACE_ID;
1057
1058
2
  if (name == NULL) return INVALID_INTERFACE_ID;
1059
1060
#ifdef WIN32
1061
  else if (isdigit(name[0]))
1062
    return (atoi(name));
1063
#endif
1064
2
  else if (!strncmp(name, "-", 1))
1065
0
    name = (char *)"stdin";
1066
1067
2
  if (ntop->getRedis()) {
1068
2
    if (ntop->getRedis()->hashGet((char *)CONST_IFACE_ID_PREFS, (char *)name,
1069
2
                                  rsp, sizeof(rsp)) == 0) {
1070
      /* Found */
1071
0
      return (atoi(rsp));
1072
2
    } else {
1073
2
      for (int i = 0; i < MAX_NUM_INTERFACE_IDS; i++) {
1074
2
        snprintf(ifidx, sizeof(ifidx), "%d", i);
1075
2
        if (ntop->getRedis()->hashGet((char *)CONST_IFACE_ID_PREFS, ifidx, rsp,
1076
2
                                      sizeof(rsp)) < 0) {
1077
2
          snprintf(rsp, sizeof(rsp), "%s", name);
1078
2
          ntop->getRedis()->hashSet((char *)CONST_IFACE_ID_PREFS, rsp, ifidx);
1079
2
          ntop->getRedis()->hashSet((char *)CONST_IFACE_ID_PREFS, ifidx, rsp);
1080
2
          return (i);
1081
2
        }
1082
2
      }
1083
1084
0
      ntop->getTrace()->traceEvent(
1085
0
          TRACE_ERROR,
1086
0
          "Interface ids exhausted. Flush redis to create new interfaces.");
1087
0
    }
1088
2
  }
1089
1090
0
  return INVALID_INTERFACE_ID; /* This can't happen, hopefully */
1091
2
}
1092
1093
/* **************************************************** */
1094
1095
62.8k
char *Utils::stringtolower(char *str) {
1096
62.8k
  int i = 0;
1097
1098
72.7k
  while (str[i] != '\0') {
1099
9.86k
    str[i] = tolower(str[i]);
1100
9.86k
    i++;
1101
9.86k
  }
1102
1103
62.8k
  return str;
1104
62.8k
}
1105
1106
/* **************************************************** */
1107
1108
/* http://en.wikipedia.org/wiki/Hostname */
1109
1110
1.90k
char *Utils::sanitizeHostName(char *str) {
1111
1.90k
  int i;
1112
1113
39.1k
  for (i = 0; str[i] != '\0'; i++) {
1114
37.2k
    if (((str[i] >= 'a') && (str[i] <= 'z')) ||
1115
37.2k
        ((str[i] >= 'A') && (str[i] <= 'Z')) ||
1116
37.2k
        ((str[i] >= '0') && (str[i] <= '9')) || (str[i] == '-') ||
1117
37.2k
        (str[i] == '_') || (str[i] == '.') ||
1118
37.2k
        (str[i] == ':') /* Used in HTTP host:port */
1119
37.2k
        || (str[i] == '@') /* Used by DNS but not a valid char */)
1120
22.6k
      ;
1121
14.5k
    else if (str[i] == '_') {
1122
0
      str[i] = '\0';
1123
0
      break;
1124
0
    } else
1125
14.5k
      str[i] = '_';
1126
37.2k
  }
1127
1128
1.90k
  return (str);
1129
1.90k
}
1130
1131
/* **************************************************** */
1132
1133
0
char *Utils::stripHTML(const char *str) {
1134
0
  if (!str) return NULL;
1135
0
  int len = strlen(str), j = 0;
1136
0
  char *stripped_str = NULL;
1137
1138
0
  stripped_str = (char *)malloc(len + 1);
1139
1140
0
  if (!stripped_str) return (NULL);
1141
1142
  // scan string
1143
0
  for (int i = 0; i < len; i++) {
1144
    // found an open '<', scan for its close
1145
0
    if (str[i] == '<') {
1146
      // charge ahead in the string until it runs out or we find what we're
1147
      // looking for
1148
0
      for (; i < len && str[i] != '>'; i++)
1149
0
        ;
1150
0
    } else {
1151
0
      stripped_str[j] = str[i];
1152
0
      j++;
1153
0
    }
1154
0
  }
1155
0
  stripped_str[j] = 0;
1156
0
  return stripped_str;
1157
0
}
1158
1159
/* **************************************************** */
1160
1161
0
char *Utils::urlDecode(const char *src, char *dst, u_int dst_len) {
1162
0
  char *ret = dst;
1163
0
  u_int i = 0;
1164
1165
0
  dst_len--; /* Leave room for \0 */
1166
0
  dst[dst_len] = 0;
1167
1168
0
  while ((*src) && (i < dst_len)) {
1169
0
    char a, b;
1170
1171
0
    if ((*src == '%') && ((a = src[1]) && (b = src[2])) &&
1172
0
        (isxdigit(a) && isxdigit(b))) {
1173
0
      char h[3] = {a, b, 0};
1174
0
      char hexval = (char)strtol(h, (char **)NULL, 16);
1175
1176
      //      if(iswprint(hexval))
1177
0
      *dst++ = hexval;
1178
1179
0
      src += 3;
1180
0
    } else if (*src == '+') {
1181
0
      *dst++ = ' ';
1182
0
      src++;
1183
0
    } else
1184
0
      *dst++ = *src++;
1185
1186
0
    i++;
1187
0
  }
1188
1189
0
  *dst++ = '\0';
1190
0
  return (ret);
1191
0
}
1192
1193
/* **************************************************** */
1194
1195
/**
1196
 * @brief Purify the HTTP parameter
1197
 *
1198
 * @param param   The parameter to purify (remove unliked chars with _)
1199
 */
1200
1201
static const char *xssAttempts[] = {
1202
    "<?import", "<applet", "<base", "<embed", "<frame", "<iframe",
1203
    "<implementation", "<import", "<link", "<meta", "<object", "<script",
1204
    "<style", "charset", "classid", "code", "codetype",
1205
    /* "data", */
1206
    "href", "http-equiv", "javascript:", "vbscript:", "vmlframe", "xlink:href",
1207
    "=", NULL};
1208
1209
/* ************************************************************ */
1210
1211
/* http://www.ascii-code.com */
1212
1213
0
bool Utils::isPrintableChar(u_char c) {
1214
0
  if (isprint(c)) return (true);
1215
1216
0
  if ((c >= 192) && (c <= 255)) return (true);
1217
1218
0
  return (false);
1219
0
}
1220
1221
/* ************************************************************ */
1222
1223
/*
1224
  The method below does basic UTF-8 validation without chacing
1225
  for UTF-8 sequences validation
1226
 */
1227
0
bool Utils:: isValidUTF8(const u_char *param, size_t length) {
1228
0
  size_t i = 0;
1229
1230
0
  while(i < length) {
1231
0
    uint8_t byte = param[i];
1232
1233
0
    if(byte < 0x80) {
1234
      // 1-byte character (ASCII)
1235
0
      i++;
1236
0
    } else if((byte >> 5) == 0b110) {
1237
      // 2-byte character
1238
0
      if(((i + 1) >= length) || ((param[i + 1] >> 6) != 0b10)) {
1239
0
  return(false);  // Invalid continuation byte
1240
0
      }
1241
0
      i += 2;
1242
0
    } else if((byte >> 4) == 0b1110) {
1243
      // 3-byte character
1244
0
      if(i + 2 >= length || (param[i + 1] >> 6) != 0b10 || (param[i + 2] >> 6) != 0b10) {
1245
0
  return(false);  // Invalid continuation byte
1246
0
      }
1247
0
      i += 3;
1248
0
    } else if((byte >> 3) == 0b11110) {
1249
      // 4-byte character
1250
0
      if(((i + 3) >= length)
1251
0
   || ((param[i + 1] >> 6) != 0b10)
1252
0
   || ((param[i + 2] >> 6) != 0b10)
1253
0
   || ((param[i + 3] >> 6) != 0b10)) {
1254
0
  return(false);  // Invalid continuation byte
1255
0
      }
1256
0
      i += 4;
1257
0
    } else {
1258
0
      return(false);  // Invalid UTF-8 sequence start byte
1259
0
    }
1260
0
  }
1261
1262
0
  return(true);
1263
0
}
1264
1265
/* ************************************************************ */
1266
1267
bool Utils::purifyHTTPparam(char *const param, bool strict, bool allowURL,
1268
0
                            bool allowDots) {
1269
0
  if(((u_char)param[0]) >= 0x80) {
1270
    /* UTF8 string */
1271
0
    bool ret = Utils::isValidUTF8((const u_char*)param, strlen(param));
1272
1273
0
    if(ret)
1274
0
      return(true);
1275
0
  }
1276
1277
0
  if(strict) {
1278
0
    for(int i = 0; xssAttempts[i] != NULL; i++) {
1279
0
      if(strstr(param, xssAttempts[i])) {
1280
0
        ntop->getTrace()->traceEvent(TRACE_WARNING,
1281
0
                                     "Found possible XSS attempt: %s [%s]",
1282
0
                                     param, xssAttempts[i]);
1283
0
        param[0] = '\0';
1284
0
        return (true);
1285
0
      }
1286
0
    }
1287
0
  }
1288
1289
0
  for(int i = 0; param[i] != '\0'; i++) {
1290
0
    bool is_good;
1291
1292
0
    if(strict) {
1293
0
      is_good = ((param[i] >= 'a') && (param[i] <= 'z')) ||
1294
0
                ((param[i] >= 'A') && (param[i] <= 'Z')) ||
1295
0
                ((param[i] >= '0') && (param[i] <= '9'))
1296
                // || (param[i] == ':')
1297
                // || (param[i] == '-')
1298
0
                || (param[i] == '_')
1299
                // || (param[i] == '/')
1300
0
                || (param[i] == '@')
1301
          // || (param[i] == ',')
1302
          // || (param[i] == '.')
1303
0
          ;
1304
0
    } else {
1305
0
      char c;
1306
0
      int new_i;
1307
1308
0
      if((u_char)param[i] == 0xC3) {
1309
        /* Latin-1 within UTF-8 - Align to ASCII encoding */
1310
0
        c = param[i + 1] | 0x40;
1311
0
        new_i = i + 1; /* We are actually validating two bytes */
1312
0
      } else {
1313
0
        c = param[i];
1314
0
        new_i = i;
1315
0
      }
1316
1317
0
      is_good = Utils::isPrintableChar(c) && (c != '<') && (c != '>') &&
1318
0
                (c != '"'); /* Prevents injections - single quotes are allowed
1319
                               and will be validated in http_lint.lua */
1320
1321
0
      if(is_good) i = new_i;
1322
0
    }
1323
1324
0
    if(is_good)
1325
0
      ; /* Good: we're on the whitelist */
1326
0
    else
1327
0
      param[i] = '_'; /* Invalid char: we discard it */
1328
1329
0
    if((i > 0) &&
1330
0
        (((!allowDots) && (param[i] == '.') && (param[i - 1] == '.')) ||
1331
0
         ((!allowURL) && ((param[i] == '/') && (param[i - 1] == '/'))) ||
1332
0
         ((param[i] == '\\') && (param[i - 1] == '\\')))) {
1333
      /* Make sure we do not have .. in the variable that can be used for future
1334
       * hacking */
1335
0
      param[i - 1] = '_', param[i] = '_'; /* Invalidate the path */
1336
0
    }
1337
0
  }
1338
1339
0
  return(false);
1340
0
}
1341
1342
/* ************************************************************ */
1343
1344
bool Utils::sendTCPData(char *host, int port, char *data,
1345
0
                        int timeout /* msec */) {
1346
0
  struct hostent *server = NULL;
1347
0
  struct sockaddr_in serv_addr;
1348
0
  int sockfd = -1;
1349
0
  int retval;
1350
0
  bool rc = false;
1351
0
  static time_t last_warn = 0;
1352
1353
0
  server = gethostbyname(host);
1354
0
  if (server == NULL) return false;
1355
1356
0
  memset((char *)&serv_addr, 0, sizeof(serv_addr));
1357
0
  serv_addr.sin_family = AF_INET;
1358
0
  memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr,
1359
0
         server->h_length);
1360
0
  serv_addr.sin_port = htons(port);
1361
1362
0
  sockfd = Utils::openSocket(AF_INET, SOCK_STREAM, 0, "sendTCPData");
1363
1364
0
  if (sockfd < 0) {
1365
0
    ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to create socket");
1366
0
    return false;
1367
0
  }
1368
1369
0
#ifndef WIN32
1370
0
  if (timeout == 0) {
1371
0
    retval = fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
1372
0
    if (retval == -1) {
1373
0
      ntop->getTrace()->traceEvent(TRACE_WARNING,
1374
0
                                   "Error setting NONBLOCK flag");
1375
0
      Utils::closeSocket(sockfd);
1376
0
      return false;
1377
0
    }
1378
0
  } else {
1379
0
    struct timeval tv_timeout;
1380
0
    tv_timeout.tv_sec = timeout / 1000;
1381
0
    tv_timeout.tv_usec = (timeout % 1000) * 1000;
1382
0
    retval = setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv_timeout,
1383
0
                        sizeof(tv_timeout));
1384
0
    if (retval == -1) {
1385
0
      ntop->getTrace()->traceEvent(
1386
0
          TRACE_WARNING, "Error setting send timeout: %s", strerror(errno));
1387
0
      Utils::closeSocket(sockfd);
1388
0
      return false;
1389
0
    }
1390
0
  }
1391
0
#endif
1392
1393
0
  if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0 &&
1394
0
      (errno == ECONNREFUSED || errno == EALREADY || errno == EAGAIN ||
1395
0
       errno == ENETUNREACH || errno == ETIMEDOUT)) {
1396
0
    time_t now = time(NULL);
1397
0
    if (now > last_warn) {
1398
0
      ntop->getTrace()->traceEvent(TRACE_WARNING,
1399
0
                                   "Could not connect to remote party");
1400
0
      last_warn = now;
1401
0
    }
1402
0
    Utils::closeSocket(sockfd);
1403
0
    return false;
1404
0
  }
1405
1406
  // ntop->getTrace()->traceEvent(TRACE_NORMAL, "Sending '%s' to %s:%d",
1407
  //   data, host, port);
1408
1409
0
  rc = true;
1410
0
  retval = send(sockfd, data, strlen(data), 0);
1411
0
  if (retval <= 0) {
1412
0
    time_t now = time(NULL);
1413
0
    if (now > last_warn) {
1414
0
      ntop->getTrace()->traceEvent(TRACE_WARNING, "Send failed: %s (%d)",
1415
0
                                   strerror(errno), errno);
1416
0
      last_warn = now;
1417
0
    }
1418
0
    rc = false;
1419
0
  }
1420
1421
0
  Utils::closeSocket(sockfd);
1422
1423
0
  return rc;
1424
0
}
1425
1426
/* **************************************************** */
1427
1428
/* holder for curl fetch */
1429
struct curl_fetcher_t {
1430
  char *const payload;
1431
  size_t cur_size;
1432
  const size_t max_size;
1433
};
1434
1435
static size_t curl_get_writefunc(void *contents, size_t size, size_t nmemb,
1436
0
                                 void *userp) {
1437
0
  size_t realsize = size * nmemb;
1438
0
  struct curl_fetcher_t *p = (struct curl_fetcher_t *)userp;
1439
1440
0
  if (!p->max_size) return realsize;
1441
1442
  /* Leave the last position for a '\0' */
1443
0
  if (p->cur_size + realsize > p->max_size - 1)
1444
0
    realsize = p->max_size - p->cur_size - 1;
1445
1446
0
  if (realsize) {
1447
0
    memcpy(&(p->payload[p->cur_size]), contents, realsize);
1448
0
    p->cur_size += realsize;
1449
0
    p->payload[p->cur_size] = 0;
1450
0
  }
1451
1452
0
  return realsize;
1453
0
}
1454
1455
/* **************************************************** */
1456
1457
/**
1458
 * @brief Implement HTTP POST of JSON data
1459
 *
1460
 * @param username  Username to be used on post or NULL if missing
1461
 * @param password  Password to be used on post or NULL if missing
1462
 * @param url       URL where to post data to
1463
 * @param json      The content of the POST
1464
 * @return true if post was successful, false otherwise.
1465
 */
1466
1467
static int curl_post_writefunc(void *ptr, size_t size, size_t nmemb,
1468
0
                               void *stream) {
1469
0
  char *str = (char *)ptr;
1470
1471
0
  ntop->getTrace()->traceEvent(TRACE_DEBUG, "[JSON] %s", str);
1472
0
  return (size * nmemb);
1473
0
}
1474
1475
/* **************************************** */
1476
1477
#ifdef HAVE_CURL_SMTP
1478
1479
struct snmp_upload_status {
1480
  char *lines;
1481
  char msg_log[1024];
1482
};
1483
1484
static int curl_debugfunc(CURL *handle, curl_infotype type, char *data,
1485
0
                          size_t size, void *userptr) {
1486
0
  char dir = '\0';
1487
1488
0
  switch (type) {
1489
0
    case CURLINFO_HEADER_IN:
1490
0
    case CURLINFO_DATA_IN:
1491
0
      dir = '<';
1492
0
      break;
1493
0
    case CURLINFO_DATA_OUT:
1494
0
    case CURLINFO_HEADER_OUT:
1495
0
      dir = '>';
1496
0
      break;
1497
0
    default:
1498
0
      break;
1499
0
  }
1500
1501
0
  if (dir) {
1502
0
    char *msg = data;
1503
1504
0
    while (*msg) {
1505
0
      char *end = strchr(msg, '\n');
1506
0
      if (!end) break;
1507
1508
0
      *end = '\0';
1509
0
      ntop->getTrace()->traceEvent(TRACE_NORMAL, "[CURL] %c %s", dir, msg);
1510
0
      *end = '\n';
1511
0
      msg = end + 1;
1512
0
    }
1513
0
  }
1514
1515
0
  return (size);
1516
0
}
1517
1518
/* **************************************** */
1519
1520
static size_t curl_smtp_payload_source(void *ptr, size_t size, size_t nmemb,
1521
0
                                       void *userp) {
1522
0
  struct snmp_upload_status *upload_ctx = (struct snmp_upload_status *)userp;
1523
1524
0
  if ((size == 0) || (nmemb == 0) || ((size * nmemb) < 1)) {
1525
0
    return 0;
1526
0
  }
1527
1528
0
  char *eol = strstr(upload_ctx->lines, "\r\n");
1529
1530
0
  if (eol) {
1531
0
    size_t len = min(size, (size_t)(eol - upload_ctx->lines + 2));
1532
0
    memcpy(ptr, upload_ctx->lines, len);
1533
0
    upload_ctx->lines += len;
1534
1535
0
    return len;
1536
0
  }
1537
1538
0
  return 0;
1539
0
}
1540
1541
#endif
1542
1543
/* **************************************** */
1544
1545
0
static void readCurlStats(CURL *curl, HTTPTranferStats *stats, lua_State *vm) {
1546
0
  curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME, &stats->namelookup);
1547
0
  curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &stats->connect);
1548
0
  curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &stats->appconnect);
1549
0
  curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &stats->pretransfer);
1550
0
  curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME, &stats->redirect);
1551
0
  curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &stats->start);
1552
0
  curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &stats->total);
1553
1554
0
  if (vm) {
1555
0
    lua_newtable(vm);
1556
1557
0
    lua_push_float_table_entry(vm, "NAMELOOKUP_TIME", stats->namelookup);
1558
0
    lua_push_float_table_entry(vm, "CONNECT_TIME", stats->connect);
1559
0
    lua_push_float_table_entry(vm, "APPCONNECT_TIME", stats->appconnect);
1560
0
    lua_push_float_table_entry(vm, "PRETRANSFER_TIME", stats->pretransfer);
1561
0
    lua_push_float_table_entry(vm, "REDIRECT_TIME", stats->redirect);
1562
0
    lua_push_float_table_entry(vm, "STARTTRANSFER_TIME", stats->start);
1563
0
    lua_push_float_table_entry(vm, "TOTAL_TIME", stats->total);
1564
1565
0
    lua_pushstring(vm, "HTTP_STATS");
1566
0
    lua_insert(vm, -2);
1567
0
    lua_settable(vm, -3);
1568
0
  }
1569
1570
0
  ntop->getTrace()->traceEvent(
1571
0
      TRACE_INFO,
1572
0
      "[NAMELOOKUP_TIME %.02f][CONNECT_TIME %.02f][APPCONNECT_TIME "
1573
0
      "%.02f][PRETRANSFER_TIME %.02f]"
1574
0
      "[REDIRECT_TIME %.02f][STARTTRANSFER_TIME %.02f][TOTAL_TIME %.02f]",
1575
0
      stats->namelookup, stats->connect, stats->appconnect, stats->pretransfer,
1576
0
      stats->redirect, stats->start, stats->total);
1577
0
}
1578
1579
/* **************************************** */
1580
1581
0
static void fillcURLProxy(CURL *curl) {
1582
0
  char *http_proxy = NULL;
1583
0
  char *http_proxy_port = NULL;
1584
0
  char *no_proxy = NULL;
1585
1586
0
  http_proxy = getenv("HTTP_PROXY");
1587
0
  if (!http_proxy) http_proxy = getenv("http_proxy");
1588
1589
0
  if (http_proxy) {
1590
0
    char proxy[1024];
1591
1592
0
    http_proxy_port = getenv("HTTP_PROXY_PORT");
1593
0
    if (!http_proxy_port) http_proxy_port = getenv("http_proxy_port");
1594
1595
0
    if (http_proxy_port)
1596
0
      snprintf(proxy, sizeof(proxy), "%s:%s", http_proxy, http_proxy_port);
1597
0
    else
1598
0
      snprintf(proxy, sizeof(proxy), "%s", http_proxy);
1599
1600
0
    curl_easy_setopt(curl, CURLOPT_PROXY, proxy);
1601
0
    curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
1602
1603
0
    no_proxy = getenv("NO_PROXY");
1604
0
    if (!no_proxy) no_proxy = getenv("no_proxy");
1605
1606
0
    if (no_proxy) {
1607
0
      char no_proxy_buf[1024];
1608
1609
0
      snprintf(no_proxy_buf, sizeof(no_proxy_buf), "%s", no_proxy);
1610
0
      curl_easy_setopt(curl, CURLOPT_NOPROXY, no_proxy_buf);
1611
0
    }
1612
0
  }
1613
0
}
1614
1615
/* **************************************** */
1616
1617
bool Utils::postHTTPJsonData(char *bearer_token, char *username, char *password,
1618
                             char *url, char *json, int timeout,
1619
0
                             HTTPTranferStats *stats) {
1620
0
  CURL *curl;
1621
0
  bool ret = false;
1622
1623
0
  curl = curl_easy_init();
1624
0
  if (curl) {
1625
0
    CURLcode res;
1626
0
    struct curl_slist *headers = NULL;
1627
1628
0
    fillcURLProxy(curl);
1629
1630
0
    memset(stats, 0, sizeof(HTTPTranferStats));
1631
0
    curl_easy_setopt(curl, CURLOPT_URL, url);
1632
1633
0
    if (bearer_token && bearer_token[0] != '\0') {
1634
0
#ifdef CURLAUTH_BEARER
1635
0
      curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
1636
0
      curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, bearer_token);
1637
#else
1638
      ntop->getTrace()->traceEvent(
1639
          TRACE_WARNING, "Bearer auth is not supported by curl (%s)", url);
1640
      return (false);
1641
#endif
1642
0
    } else if ((username && (username[0] != '\0')) ||
1643
0
               (password && (password[0] != '\0'))) {
1644
0
      char auth[64];
1645
1646
0
      snprintf(auth, sizeof(auth), "%s:%s", username ? username : "",
1647
0
               password ? password : "");
1648
0
      curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
1649
0
      curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
1650
0
    }
1651
1652
0
    if (!strncmp(url, "https", 5) && ntop->getPrefs()->do_insecure_tls()) {
1653
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
1654
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
1655
0
    }
1656
1657
0
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
1658
0
    headers = curl_slist_append(headers, "Content-Type: application/json");
1659
0
    headers = curl_slist_append(headers,
1660
0
                                "Expect:");  // Disable 100-continue as it may
1661
                                             // cause issues (e.g. in InfluxDB)
1662
0
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
1663
0
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json);
1664
0
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(json));
1665
0
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_post_writefunc);
1666
1667
0
    if (timeout) {
1668
0
      curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
1669
0
      curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
1670
#ifdef CURLOPT_CONNECTTIMEOUT_MS
1671
      curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout * 1000);
1672
#endif
1673
0
    }
1674
1675
0
    res = curl_easy_perform(curl);
1676
1677
0
    if (res != CURLE_OK) {
1678
0
      ntop->getTrace()->traceEvent(TRACE_WARNING,
1679
0
                                   "Unable to post data to (%s): %s", url,
1680
0
                                   curl_easy_strerror(res));
1681
0
    } else {
1682
0
      long http_code = 0;
1683
1684
0
      ntop->getTrace()->traceEvent(TRACE_INFO, "Posted JSON to %s", url);
1685
0
      readCurlStats(curl, stats, NULL);
1686
1687
0
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
1688
      // Success if http_code is 2xx, failure otherwise
1689
0
      if (http_code >= 200 && http_code <= 299)
1690
0
        ret = true;
1691
0
      else
1692
0
        ntop->getTrace()->traceEvent(
1693
0
            TRACE_WARNING, "Unexpected HTTP response code received %u",
1694
0
            http_code);
1695
0
    }
1696
1697
    /* always cleanup */
1698
0
    curl_slist_free_all(headers);
1699
0
    curl_easy_cleanup(curl);
1700
0
  } else
1701
0
    ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to initialize curl");
1702
1703
0
  return (ret);
1704
0
}
1705
1706
/* **************************************** */
1707
1708
bool Utils::postHTTPJsonData(char *bearer_token, char *username, char *password,
1709
                             char *url, char *json, int timeout,
1710
                             HTTPTranferStats *stats, char *return_data,
1711
0
                             int return_data_size, int *response_code) {
1712
0
  CURL *curl;
1713
0
  bool ret = false;
1714
1715
0
  curl = curl_easy_init();
1716
1717
0
  if (curl) {
1718
0
    CURLcode res;
1719
0
    struct curl_slist *headers = NULL;
1720
0
    curl_fetcher_t fetcher = {/* .payload =  */ return_data,
1721
0
                              /* .cur_size = */ 0,
1722
0
                              /* .max_size = */ (size_t)return_data_size};
1723
1724
0
    fillcURLProxy(curl);
1725
1726
0
    memset(stats, 0, sizeof(HTTPTranferStats));
1727
0
    curl_easy_setopt(curl, CURLOPT_URL, url);
1728
1729
0
    if (bearer_token && bearer_token[0] != '\0') {
1730
0
#ifdef CURLAUTH_BEARER
1731
0
      curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
1732
0
      curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, bearer_token);
1733
#else
1734
      ntop->getTrace()->traceEvent(
1735
          TRACE_WARNING, "Bearer auth is not supported by curl (%s)", url);
1736
      return (false);
1737
#endif
1738
0
    } else if ((username && (username[0] != '\0')) ||
1739
0
               (password && (password[0] != '\0'))) {
1740
0
      char auth[64];
1741
1742
0
      snprintf(auth, sizeof(auth), "%s:%s", username ? username : "",
1743
0
               password ? password : "");
1744
0
      curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
1745
0
      curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
1746
0
    }
1747
1748
0
    if (!strncmp(url, "https", 5) && ntop->getPrefs()->do_insecure_tls()) {
1749
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
1750
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
1751
0
    }
1752
1753
0
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
1754
0
    headers = curl_slist_append(headers, "Content-Type: application/json");
1755
0
    headers = curl_slist_append(headers,
1756
0
                                "Expect:");  // Disable 100-continue as it may
1757
                                             // cause issues (e.g. in InfluxDB)
1758
0
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
1759
0
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json);
1760
0
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(json));
1761
0
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fetcher);
1762
0
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_get_writefunc);
1763
1764
0
    if (timeout) {
1765
0
      curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
1766
0
      curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
1767
#ifdef CURLOPT_CONNECTTIMEOUT_MS
1768
      curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout * 1000);
1769
#endif
1770
0
    }
1771
1772
0
    res = curl_easy_perform(curl);
1773
1774
0
    if (res != CURLE_OK) {
1775
0
      ntop->getTrace()->traceEvent(TRACE_WARNING,
1776
0
                                   "Unable to post data to (%s): %s", url,
1777
0
                                   curl_easy_strerror(res));
1778
0
    } else {
1779
0
      long rc;
1780
0
      ntop->getTrace()->traceEvent(TRACE_INFO, "Posted JSON to %s", url);
1781
0
      readCurlStats(curl, stats, NULL);
1782
0
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rc);
1783
0
      *response_code = rc;
1784
0
      ret = true;
1785
0
    }
1786
1787
    /* always cleanup */
1788
0
    curl_slist_free_all(headers);
1789
0
    curl_easy_cleanup(curl);
1790
0
  }
1791
1792
0
  return (ret);
1793
0
}
1794
1795
/* **************************************** */
1796
1797
static size_t read_callback(void *ptr, size_t size, size_t nmemb,
1798
0
                            void *stream) {
1799
0
  return (fread(ptr, size, nmemb, (FILE *)stream));
1800
0
}
1801
1802
bool Utils::postHTTPTextFile(lua_State *vm, char *username, char *password,
1803
                             char *url, char *path, int timeout,
1804
0
                             HTTPTranferStats *stats) {
1805
0
  CURL *curl;
1806
0
  bool ret = true;
1807
0
  struct stat buf;
1808
0
  size_t file_len;
1809
0
  FILE *fd;
1810
1811
0
  if (stat(path, &buf) != 0) return (false);
1812
1813
0
  if ((fd = fopen(path, "rb")) == NULL)
1814
0
    return (false);
1815
0
  else
1816
0
    file_len = (size_t)buf.st_size;
1817
1818
0
  curl = curl_easy_init();
1819
1820
0
  if (curl) {
1821
0
    CURLcode res;
1822
0
    DownloadState *state = NULL;
1823
0
    struct curl_slist *headers = NULL;
1824
1825
0
    fillcURLProxy(curl);
1826
1827
0
    memset(stats, 0, sizeof(HTTPTranferStats));
1828
0
    curl_easy_setopt(curl, CURLOPT_URL, url);
1829
1830
0
    if ((username && (username[0] != '\0')) ||
1831
0
        (password && (password[0] != '\0'))) {
1832
0
      char auth[64];
1833
1834
0
      snprintf(auth, sizeof(auth), "%s:%s", username ? username : "",
1835
0
               password ? password : "");
1836
0
      curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
1837
0
      curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
1838
0
    }
1839
1840
0
    if (!strncmp(url, "https", 5) && ntop->getPrefs()->do_insecure_tls()) {
1841
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
1842
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
1843
0
    }
1844
1845
0
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
1846
0
    headers =
1847
0
        curl_slist_append(headers, "Content-Type: text/plain; charset=utf-8");
1848
0
    headers = curl_slist_append(headers,
1849
0
                                "Expect:");  // Disable 100-continue as it may
1850
                                             // cause issues (e.g. in InfluxDB)
1851
0
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
1852
1853
0
    curl_easy_setopt(curl, CURLOPT_READDATA, fd);
1854
0
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
1855
0
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)file_len);
1856
1857
0
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
1858
0
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
1859
1860
#ifdef CURLOPT_CONNECTTIMEOUT_MS
1861
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout * 1000);
1862
#endif
1863
1864
0
    state = (DownloadState *)malloc(sizeof(DownloadState));
1865
0
    if (state != NULL) {
1866
0
      memset(state, 0, sizeof(DownloadState));
1867
1868
0
      curl_easy_setopt(curl, CURLOPT_WRITEDATA, state);
1869
0
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writefunc_to_lua);
1870
0
      curl_easy_setopt(curl, CURLOPT_HEADERDATA, state);
1871
0
      curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_hdf);
1872
1873
0
      state->vm = vm, state->header_over = 0, state->return_content = true;
1874
0
    } else {
1875
0
      ntop->getTrace()->traceEvent(TRACE_WARNING, "Out of memory");
1876
0
      curl_easy_cleanup(curl);
1877
0
      if (vm) lua_pushnil(vm);
1878
0
      return (false);
1879
0
    }
1880
1881
0
    if (vm) lua_newtable(vm);
1882
1883
0
    res = curl_easy_perform(curl);
1884
1885
0
    if (res != CURLE_OK) {
1886
0
      ntop->getTrace()->traceEvent(TRACE_INFO,
1887
0
                                   "Unable to post data to (%s): %s", url,
1888
0
                                   curl_easy_strerror(res));
1889
0
      lua_push_str_table_entry(vm, "error_msg", curl_easy_strerror(res));
1890
0
      ret = false;
1891
0
    } else {
1892
0
      ntop->getTrace()->traceEvent(TRACE_INFO, "Posted JSON to %s", url);
1893
0
      readCurlStats(curl, stats, NULL);
1894
1895
0
      if (vm) {
1896
0
        long response_code;
1897
0
        lua_push_str_table_entry(vm, "CONTENT", state->outbuf);
1898
0
        lua_push_uint64_table_entry(vm, "CONTENT_LEN", state->num_bytes);
1899
1900
0
        if (curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code) ==
1901
0
            CURLE_OK)
1902
0
          lua_push_uint64_table_entry(vm, "RESPONSE_CODE", response_code);
1903
0
      }
1904
0
    }
1905
1906
0
    if (state) free(state);
1907
1908
0
    fclose(fd);
1909
1910
    /* always cleanup */
1911
0
    curl_slist_free_all(headers);
1912
0
    curl_easy_cleanup(curl);
1913
0
  }
1914
1915
0
  return (ret);
1916
0
}
1917
1918
/* **************************************** */
1919
1920
bool Utils::sendMail(lua_State *vm, char *from, char *to, char *cc,
1921
                     char *message, char *smtp_server, char *username,
1922
0
                     char *password, bool use_proxy, bool verbose) {
1923
0
  bool ret = true;
1924
0
  const char *ret_str = "";
1925
1926
0
#ifdef HAVE_CURL_SMTP
1927
0
  CURL *curl;
1928
0
  CURLcode res;
1929
0
  struct curl_slist *recipients = NULL;
1930
0
  struct snmp_upload_status *upload_ctx =
1931
0
      (struct snmp_upload_status *)calloc(1, sizeof(struct snmp_upload_status));
1932
1933
0
  if (!upload_ctx) {
1934
0
    ret = false;
1935
0
    goto out;
1936
0
  }
1937
1938
0
  upload_ctx->lines = message;
1939
0
  curl = curl_easy_init();
1940
1941
0
  if (curl) {
1942
1943
0
    if (use_proxy) {
1944
0
      fillcURLProxy(curl);
1945
0
    }
1946
1947
0
    if (username != NULL && password != NULL) {
1948
0
      curl_easy_setopt(curl, CURLOPT_USERNAME, username);
1949
0
      curl_easy_setopt(curl, CURLOPT_PASSWORD, password);
1950
0
    }
1951
1952
0
    curl_easy_setopt(curl, CURLOPT_URL, smtp_server);
1953
1954
0
    if (strncmp(smtp_server, "smtps://", 8) == 0)
1955
0
      curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
1956
0
    else if (strncmp(smtp_server, "smtp://", 7) == 0)
1957
0
      curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_NONE);
1958
0
    else /* Try using SSL */
1959
0
      curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
1960
1961
0
    if (ntop->getPrefs()->do_insecure_tls()) {
1962
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
1963
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
1964
0
    }
1965
1966
0
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from);
1967
0
    if(verbose) ntop->getTrace()->traceEvent(TRACE_NORMAL, "Adding from: %s", from);
1968
    
1969
0
    recipients = curl_slist_append(recipients, to);
1970
0
    if(verbose) ntop->getTrace()->traceEvent(TRACE_NORMAL, "Adding to: %s", to);
1971
    
1972
0
    if (cc && cc[0]) {
1973
0
      char *ccs = strdup(cc);
1974
1975
0
      if(ccs) {
1976
0
  char *tmp, *rec;
1977
1978
0
  rec = strtok_r(ccs, ",", &tmp);
1979
1980
0
  while(rec != NULL) {
1981
0
    if(verbose) ntop->getTrace()->traceEvent(TRACE_NORMAL, "Adding cc: %s", rec);
1982
0
    recipients = curl_slist_append(recipients, rec);
1983
0
    rec = strtok_r(NULL, ",", &tmp);
1984
0
  }
1985
1986
0
  free(ccs);
1987
0
      }
1988
0
    }
1989
0
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
1990
1991
0
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, curl_smtp_payload_source);
1992
0
    curl_easy_setopt(curl, CURLOPT_READDATA, upload_ctx);
1993
0
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
1994
1995
0
    if (ntop->getTrace()->get_trace_level() >= TRACE_LEVEL_DEBUG
1996
0
        || verbose) {
1997
      /* Show verbose message trace */
1998
0
      curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
1999
0
      curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_debugfunc);
2000
0
      curl_easy_setopt(curl, CURLOPT_DEBUGDATA, upload_ctx);
2001
0
    }
2002
2003
0
    res = curl_easy_perform(curl);
2004
0
    ret_str = curl_easy_strerror(res);
2005
2006
0
    if (res != CURLE_OK) {
2007
0
      ntop->getTrace()->traceEvent(TRACE_WARNING,
2008
0
                                   "Unable to send email to (%s): %s. Run "
2009
0
                                   "ntopng with -v6 for more details.",
2010
0
                                   smtp_server, curl_easy_strerror(res));
2011
0
      ret = false;
2012
0
    }
2013
2014
0
    curl_slist_free_all(recipients);
2015
2016
    /* NOTE: connection could be reused */
2017
0
    curl_easy_cleanup(curl);
2018
0
  }
2019
2020
0
  free(upload_ctx);
2021
2022
0
out:
2023
#else
2024
  ret = false;
2025
  ret_str = "SMTP support is not available";
2026
#endif
2027
2028
0
  if (vm) {
2029
    /*
2030
    If a lua VM has been passed as parameter, return code and return message are
2031
    pushed into the lua stack.
2032
    */
2033
0
    lua_newtable(vm);
2034
0
    lua_push_bool_table_entry(vm, "success", ret);
2035
0
    lua_push_str_table_entry(vm, "msg", ret_str);
2036
0
  } else if (!ret)
2037
    /*
2038
      If not lua VM has been passed, in case of error, a message is logged to
2039
      stdout
2040
     */
2041
0
    ntop->getTrace()->traceEvent(TRACE_WARNING,
2042
0
                                 "Unable to send email to (%s): %s. Run ntopng "
2043
0
                                 "with -v6 for more details.",
2044
0
                                 smtp_server, ret_str);
2045
0
  return ret;
2046
0
}
2047
2048
/* **************************************** */
2049
2050
/* curl calls this routine to get more data */
2051
static size_t curl_writefunc_to_lua(char *buffer, size_t size, size_t nitems,
2052
0
                                    void *userp) {
2053
0
  DownloadState *state = (DownloadState *)userp;
2054
0
  int len = size * nitems, diff;
2055
2056
0
  if (state->header_over == 0) {
2057
    /* We need to parse the header as this is the first call for the body */
2058
0
    char *tmp, *element;
2059
2060
0
    state->outbuf[state->num_bytes] = 0;
2061
0
    element = strtok_r(state->outbuf, "\r\n", &tmp);
2062
0
    if (element) element = strtok_r(NULL, "\r\n", &tmp);
2063
2064
0
    lua_newtable(state->vm);
2065
2066
0
    while (element) {
2067
0
      char *column = strchr(element, ':');
2068
2069
0
      if (!column) break;
2070
2071
0
      column[0] = '\0';
2072
2073
      /* Put everything in lowercase */
2074
0
      for (int i = 0; element[i] != '\0'; i++) element[i] = tolower(element[i]);
2075
0
      lua_push_str_table_entry(state->vm, element, &column[1]);
2076
2077
0
      element = strtok_r(NULL, "\r\n", &tmp);
2078
0
    }
2079
2080
0
    lua_pushstring(state->vm, "HTTP_HEADER");
2081
0
    lua_insert(state->vm, -2);
2082
0
    lua_settable(state->vm, -3);
2083
2084
0
    state->num_bytes = 0, state->header_over = 1;
2085
0
  }
2086
2087
0
  if (state->return_content) {
2088
0
    diff = sizeof(state->outbuf) - state->num_bytes - 1;
2089
2090
0
    if (diff > 0) {
2091
0
      int buff_diff = min(diff, len);
2092
2093
0
      if (buff_diff > 0) {
2094
0
        strncpy(&state->outbuf[state->num_bytes], buffer, buff_diff);
2095
0
        state->num_bytes += buff_diff;
2096
0
        state->outbuf[state->num_bytes] = '\0';
2097
0
      }
2098
0
    }
2099
0
  }
2100
2101
0
  return (len);
2102
0
}
2103
2104
/* **************************************** */
2105
2106
static size_t curl_writefunc_to_file(void *ptr, size_t size, size_t nmemb,
2107
0
                                     void *stream) {
2108
0
  size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);
2109
0
  return written;
2110
0
}
2111
2112
/* **************************************** */
2113
2114
/* Same as the above function but only for header */
2115
0
static size_t curl_hdf(char *buffer, size_t size, size_t nitems, void *userp) {
2116
0
  DownloadState *state = (DownloadState *)userp;
2117
0
  int len = size * nitems;
2118
0
  int diff = sizeof(state->outbuf) - state->num_bytes - 1;
2119
2120
0
  if (diff > 0) {
2121
0
    int buff_diff = min(diff, len);
2122
2123
0
    if (buff_diff > 0) {
2124
0
      strncpy(&state->outbuf[state->num_bytes], buffer, buff_diff);
2125
0
      state->num_bytes += buff_diff;
2126
0
      state->outbuf[state->num_bytes] = '\0';
2127
0
    }
2128
0
  }
2129
2130
0
  return (len);
2131
0
}
2132
2133
/* **************************************** */
2134
2135
0
bool Utils::progressCanContinue(ProgressState *progressState) {
2136
0
  struct mg_connection *conn;
2137
0
  time_t now = time(0);
2138
2139
0
  if (progressState->vm && ((now - progressState->last_conn_check) >= 1) &&
2140
0
      (conn = getLuaVMUserdata(progressState->vm, conn))) {
2141
0
    progressState->last_conn_check = now;
2142
2143
0
    if (!mg_is_client_connected(conn))
2144
      /* connection to the client was closed, should not continue */
2145
0
      return (false);
2146
0
  }
2147
2148
0
  return (true);
2149
0
}
2150
2151
/* **************************************** */
2152
2153
static int progress_callback(void *clientp, double dltotal, double dlnow,
2154
0
                             double ultotal, double ulnow) {
2155
0
  ProgressState *progressState = (ProgressState *)clientp;
2156
2157
0
  progressState->bytes.download = (u_int32_t)dlnow,
2158
0
  progressState->bytes.upload = (u_int32_t)ulnow;
2159
2160
0
  return Utils::progressCanContinue(progressState) ? 0 /* continue */
2161
0
                                                   : 1 /* stop transfer */;
2162
0
}
2163
2164
/* **************************************** */
2165
2166
/* form_data is in format param=value&param1=&value1... */
2167
bool Utils::httpGetPost(lua_State *vm, char *url,
2168
                        /* NOTE if user_header_token != NULL, username AND
2169
                           password are ignored, and vice-versa */
2170
                        char *username, char *password, char *user_header_token,
2171
                        int timeout, bool return_content,
2172
                        bool use_cookie_authentication, HTTPTranferStats *stats,
2173
                        const char *form_data, char *write_fname,
2174
0
                        bool follow_redirects, int ip_version) {
2175
0
  CURL *curl = curl_easy_init();
2176
0
  FILE *out_f = NULL;
2177
0
  bool ret = true;
2178
0
  char tokenBuffer[64];
2179
0
  bool used_tokenBuffer = false;
2180
2181
0
  if (curl) {
2182
0
    DownloadState *state = NULL;
2183
0
    ProgressState progressState;
2184
0
    CURLcode curlcode;
2185
0
    struct curl_slist *headers = NULL;
2186
0
    long response_code;
2187
0
    char *content_type, *redirection;
2188
0
    char ua[64];
2189
2190
0
    fillcURLProxy(curl);
2191
2192
0
    memset(stats, 0, sizeof(HTTPTranferStats));
2193
0
    curl_easy_setopt(curl, CURLOPT_URL, url);
2194
2195
0
    if (user_header_token != NULL) {
2196
0
      snprintf(tokenBuffer, sizeof(tokenBuffer), "Authorization: Token %s",
2197
0
               user_header_token);
2198
0
    } else {
2199
0
      tokenBuffer[0] = '\0';
2200
2201
0
      if (username || password) {
2202
0
        char auth[64];
2203
2204
0
        if (use_cookie_authentication) {
2205
0
          snprintf(auth, sizeof(auth), "user=%s; password=%s",
2206
0
                   username ? username : "", password ? password : "");
2207
0
          curl_easy_setopt(curl, CURLOPT_COOKIE, auth);
2208
0
        } else {
2209
0
          if (username && (username[0] != '\0')) {
2210
0
            snprintf(auth, sizeof(auth), "%s:%s", username ? username : "",
2211
0
                     password ? password : "");
2212
0
            curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
2213
0
            curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
2214
0
          }
2215
0
        }
2216
0
      }
2217
0
    }
2218
2219
0
    if (!strncmp(url, "https", 5) && ntop->getPrefs()->do_insecure_tls()) {
2220
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
2221
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
2222
2223
#ifdef CURLOPT_SSL_ENABLE_ALPN
2224
      curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 1L); /* Enable ALPN */
2225
#endif
2226
2227
#ifdef CURLOPT_SSL_ENABLE_NPN
2228
      curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_NPN,
2229
                       1L); /* Negotiate HTTP/2 if available */
2230
#endif
2231
0
    }
2232
2233
0
    if (form_data) {
2234
      /* This is a POST request */
2235
0
      curl_easy_setopt(curl, CURLOPT_POST, 1L);
2236
0
      curl_easy_setopt(curl, CURLOPT_POSTFIELDS, form_data);
2237
0
      curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(form_data));
2238
2239
0
      if (form_data[0] == '{' /* JSON */) {
2240
0
        headers = curl_slist_append(headers, "Content-Type: application/json");
2241
2242
0
        if (tokenBuffer[0] != '\0') {
2243
0
          headers = curl_slist_append(headers, tokenBuffer);
2244
0
          used_tokenBuffer = true;
2245
0
        }
2246
0
      }
2247
0
    }
2248
2249
0
    if ((tokenBuffer[0] != '\0') && (!used_tokenBuffer)) {
2250
0
      snprintf(tokenBuffer, sizeof(tokenBuffer), "Authorization: Token %s",
2251
0
               user_header_token);
2252
0
      headers = curl_slist_append(headers, tokenBuffer);
2253
0
      used_tokenBuffer = true;
2254
0
    }
2255
2256
0
    if (headers != NULL) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
2257
2258
0
    if (write_fname) {
2259
0
      ntop->fixPath(write_fname);
2260
0
      out_f = fopen(write_fname, "wb");
2261
2262
0
      if (out_f == NULL) {
2263
0
        ntop->getTrace()->traceEvent(TRACE_ERROR, "Could not open %s for write",
2264
0
                                     write_fname, strerror(errno));
2265
0
        curl_easy_cleanup(curl);
2266
0
        if (vm) lua_pushnil(vm);
2267
0
        return (false);
2268
0
      }
2269
2270
0
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writefunc_to_file);
2271
0
      curl_easy_setopt(curl, CURLOPT_WRITEDATA, out_f);
2272
0
    } else {
2273
0
      state = (DownloadState *)malloc(sizeof(DownloadState));
2274
0
      if (state != NULL) {
2275
0
        memset(state, 0, sizeof(DownloadState));
2276
2277
0
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, state);
2278
0
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writefunc_to_lua);
2279
0
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, state);
2280
0
        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_hdf);
2281
2282
0
        state->vm = vm, state->header_over = 0,
2283
0
        state->return_content = return_content;
2284
0
      } else {
2285
0
        ntop->getTrace()->traceEvent(TRACE_WARNING, "Out of memory");
2286
0
        curl_easy_cleanup(curl);
2287
0
        if (vm) lua_pushnil(vm);
2288
0
        return (false);
2289
0
      }
2290
0
    }
2291
2292
0
    if (follow_redirects) {
2293
0
      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
2294
0
      curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);
2295
0
    }
2296
2297
0
    if (ip_version == 4)
2298
0
      curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
2299
0
    else if (ip_version == 6)
2300
0
      curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
2301
2302
0
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
2303
0
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
2304
0
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
2305
2306
0
    if (!form_data) {
2307
      /* A GET request, track client connection status */
2308
0
      memset(&progressState, 0, sizeof(progressState));
2309
0
      progressState.vm = vm;
2310
0
      curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
2311
0
      curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);
2312
0
      curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progressState);
2313
0
    }
2314
2315
#ifdef CURLOPT_CONNECTTIMEOUT_MS
2316
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout * 1000);
2317
#endif
2318
2319
0
    if (ntop->getTrace()->get_trace_level() > TRACE_LEVEL_NORMAL)
2320
0
      curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
2321
2322
0
    snprintf(ua, sizeof(ua), "%s/%s/%s", PACKAGE_STRING, PACKAGE_MACHINE,
2323
0
             PACKAGE_OS);
2324
0
    curl_easy_setopt(curl, CURLOPT_USERAGENT, ua);
2325
    // curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl/7.54.0");
2326
2327
0
    if (vm) lua_newtable(vm);
2328
2329
0
    if ((curlcode = curl_easy_perform(curl)) == CURLE_OK) {
2330
0
      if (return_content && vm) {
2331
0
        lua_push_str_table_entry(vm, "CONTENT", state->outbuf);
2332
0
        lua_push_uint64_table_entry(vm, "CONTENT_LEN", state->num_bytes);
2333
0
      }
2334
2335
0
      if (vm) {
2336
0
        char *ip = NULL;
2337
2338
0
        if (!curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &ip) && ip)
2339
0
          lua_push_str_table_entry(vm, "RESOLVED_IP", ip);
2340
0
      }
2341
2342
0
      ret = true;
2343
0
    } else {
2344
0
      if (vm)
2345
0
        lua_push_str_table_entry(vm, "ERROR", curl_easy_strerror(curlcode));
2346
0
      ret = false;
2347
0
    }
2348
2349
0
    if (vm) {
2350
0
      readCurlStats(curl, stats, vm);
2351
2352
0
      if (curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code) ==
2353
0
          CURLE_OK)
2354
0
        lua_push_uint64_table_entry(vm, "RESPONSE_CODE", response_code);
2355
2356
0
      if ((curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type) ==
2357
0
           CURLE_OK) &&
2358
0
          content_type)
2359
0
        lua_push_str_table_entry(vm, "CONTENT_TYPE", content_type);
2360
2361
0
      if (curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &redirection) ==
2362
0
          CURLE_OK)
2363
0
        lua_push_str_table_entry(vm, "EFFECTIVE_URL", redirection);
2364
2365
0
      if (!form_data) {
2366
0
        lua_push_uint64_table_entry(vm, "BYTES_DOWNLOAD",
2367
0
                                    progressState.bytes.download);
2368
0
        lua_push_uint64_table_entry(vm, "BYTES_UPLOAD",
2369
0
                                    progressState.bytes.upload);
2370
0
      }
2371
2372
0
      if (!ret) lua_push_bool_table_entry(vm, "IS_PARTIAL", true);
2373
0
    }
2374
2375
0
    if (state) free(state);
2376
2377
    /* always cleanup */
2378
0
    if (headers != NULL) curl_slist_free_all(headers);
2379
0
    curl_easy_cleanup(curl);
2380
0
  }
2381
2382
0
  if (out_f) fclose(out_f);
2383
2384
0
  return (ret);
2385
0
}
2386
2387
/* **************************************** */
2388
2389
long Utils::httpGet(const char *url,
2390
                    /* NOTE if user_header_token != NULL, username AND password
2391
                       are ignored, and vice-versa */
2392
                    const char *username, const char *password,
2393
                    const char *user_header_token, int timeout,
2394
0
                    char *const resp, const u_int resp_len) {
2395
0
  CURL *curl = curl_easy_init();
2396
0
  long response_code = 0;
2397
0
  char tokenBuffer[64];
2398
2399
0
  if (curl) {
2400
0
    struct curl_slist *headers = NULL;
2401
0
    char *content_type;
2402
0
    char ua[64];
2403
0
    curl_fetcher_t fetcher = {/* .payload =  */ resp,
2404
0
                              /* .cur_size = */ 0,
2405
0
                              /* .max_size = */ resp_len};
2406
2407
0
    fillcURLProxy(curl);
2408
2409
0
    curl_easy_setopt(curl, CURLOPT_URL, url);
2410
2411
0
    if (user_header_token == NULL) {
2412
0
      if (username || password) {
2413
0
        char auth[64];
2414
2415
0
        snprintf(auth, sizeof(auth), "%s:%s", username ? username : "",
2416
0
                 password ? password : "");
2417
0
        curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
2418
0
        curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
2419
0
      }
2420
0
    } else {
2421
0
      snprintf(tokenBuffer, sizeof(tokenBuffer), "Authorization: Token %s",
2422
0
               user_header_token);
2423
0
      headers = curl_slist_append(headers, tokenBuffer);
2424
0
    }
2425
2426
0
    if (headers != NULL) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
2427
2428
0
    if (!strncmp(url, "https", 5) && ntop->getPrefs()->do_insecure_tls()) {
2429
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
2430
0
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
2431
0
    }
2432
2433
0
    if (resp && resp_len) {
2434
0
      curl_easy_setopt(curl, CURLOPT_WRITEDATA, &fetcher);
2435
0
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_get_writefunc);
2436
0
    }
2437
2438
0
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
2439
0
    curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);
2440
0
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
2441
0
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
2442
0
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
2443
2444
#ifdef CURLOPT_CONNECTTIMEOUT_MS
2445
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, timeout * 1000);
2446
#endif
2447
2448
0
    snprintf(ua, sizeof(ua), "%s [%s][%s]", PACKAGE_STRING, PACKAGE_MACHINE,
2449
0
             PACKAGE_OS);
2450
0
    curl_easy_setopt(curl, CURLOPT_USERAGENT, ua);
2451
2452
0
    if (curl_easy_perform(curl) == CURLE_OK) {
2453
0
      if ((curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &content_type) !=
2454
0
           CURLE_OK) ||
2455
0
          (curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code) !=
2456
0
           CURLE_OK))
2457
0
        response_code = 0;
2458
0
    }
2459
2460
    /* always cleanup */
2461
0
    if (headers != NULL) curl_slist_free_all(headers);
2462
0
    curl_easy_cleanup(curl);
2463
0
  }
2464
2465
0
  return response_code;
2466
0
}
2467
2468
/* **************************************** */
2469
2470
0
char *Utils::getURL(char *url, char *buf, u_int buf_len) {
2471
0
  struct stat s;
2472
2473
0
  if (!ntop->getPrefs()->is_pro_edition()) return (url);
2474
2475
0
  snprintf(buf, buf_len, "%s/lua/pro%s",
2476
0
           ntop->get_HTTPserver()->get_scripts_dir(), &url[4]);
2477
2478
0
  ntop->fixPath(buf);
2479
0
  if ((stat(buf, &s) == 0) && (S_ISREG(s.st_mode))) {
2480
0
    u_int l = strlen(ntop->get_HTTPserver()->get_scripts_dir());
2481
0
    char *new_url = &buf[l];
2482
2483
    // ntop->getTrace()->traceEvent(TRACE_NORMAL, "===>>> %s", new_url);
2484
0
    return (new_url);
2485
0
  } else
2486
0
    return (url);
2487
0
}
2488
2489
/* **************************************************** */
2490
2491
/* URL encodes the given string. The caller must free the returned string after
2492
 * use. */
2493
0
char *Utils::urlEncode(const char *url) {
2494
0
  CURL *curl;
2495
2496
0
  if (url) {
2497
0
    curl = curl_easy_init();
2498
2499
0
    if (curl) {
2500
0
      char *escaped = curl_easy_escape(curl, url, strlen(url));
2501
0
      char *output = strdup(escaped);
2502
2503
0
      curl_free(escaped);
2504
0
      curl_easy_cleanup(curl);
2505
2506
0
      return output;
2507
0
    }
2508
0
  }
2509
2510
0
  return NULL;
2511
0
}
2512
2513
/* **************************************** */
2514
2515
// The following one initializes a new string.
2516
#ifdef NOTUSED
2517
static void newString(String *str) {
2518
  str->l = 0;
2519
  str->s = (char *)malloc((str->l) + 1);
2520
  if (str->s == NULL) {
2521
    fprintf(stderr, "ERROR: malloc() failed!\n");
2522
    exit(EXIT_FAILURE);
2523
  } else {
2524
    str->s[0] = '\0';
2525
  }
2526
  return;
2527
}
2528
#endif
2529
2530
/* **************************************** */
2531
2532
8
ticks Utils::getticks() {
2533
#ifdef WIN32
2534
  struct timeval tv;
2535
  gettimeofday(&tv, 0);
2536
2537
  return (((ticks)tv.tv_usec) + (((ticks)tv.tv_sec) * 1000000LL));
2538
#else
2539
#if defined(__i386__)
2540
  ticks x;
2541
2542
  __asm__ volatile(".byte 0x0f, 0x31" : "=A"(x));
2543
  return x;
2544
#elif defined(__x86_64__)
2545
8
  u_int32_t a, d;
2546
2547
8
  asm volatile("rdtsc" : "=a"(a), "=d"(d));
2548
8
  return (((ticks)a) | (((ticks)d) << 32));
2549
2550
  /*
2551
    __asm __volatile("rdtsc" : "=A" (x));
2552
    return (x);
2553
  */
2554
#else /* ARM, MIPS.... (not very fast) */
2555
  struct timeval tv;
2556
  gettimeofday(&tv, 0);
2557
2558
  return (((ticks)tv.tv_usec) + (((ticks)tv.tv_sec) * 1000000LL));
2559
#endif
2560
8
#endif
2561
8
}
2562
2563
/* **************************************** */
2564
2565
2
ticks Utils::gettickspersec() {
2566
2
#if !(defined(__arm__) || defined(__mips__))
2567
2
  ticks tick_start, tick_delta, ret;
2568
2569
  /* computing usleep delay */
2570
2
  tick_start = Utils::getticks();
2571
2
  _usleep(1000);
2572
2
  tick_delta = (Utils::getticks() - tick_start) / 1000;
2573
2574
  /* computing CPU freq */
2575
2
  tick_start = Utils::getticks();
2576
2
  _usleep(1001);
2577
2578
2
  ret = (Utils::getticks() - tick_start - tick_delta) * 1000; /*kHz -> Hz*/
2579
2
  if (ret == 0) ret = 1; /* Avoid invalid values */
2580
2581
2
  return (ret);
2582
#else
2583
  return CLOCKS_PER_SEC;
2584
#endif
2585
2
}
2586
2587
/* **************************************** */
2588
2589
static bool scan_dir(const char *dir_name,
2590
                     list<pair<struct dirent *, char *> > *dirlist,
2591
0
                     unsigned long *total) {
2592
0
  int path_length;
2593
0
  char path[MAX_PATH + 2];
2594
0
  DIR *d;
2595
0
  struct stat buf;
2596
2597
0
  d = opendir(dir_name);
2598
0
  if (!d) return false;
2599
2600
0
  while (1) {
2601
0
    struct dirent *entry;
2602
0
    const char *d_name;
2603
2604
0
    entry = readdir(d);
2605
0
    if (!entry) break;
2606
0
    d_name = entry->d_name;
2607
2608
0
    if (entry->d_type & DT_REG) {
2609
0
      snprintf(path, sizeof(path), "%s/%s", dir_name, entry->d_name);
2610
0
      if (!stat(path, &buf)) {
2611
0
        struct dirent *temp = (struct dirent *)malloc(sizeof(struct dirent));
2612
0
        memcpy(temp, entry, sizeof(struct dirent));
2613
0
        dirlist->push_back(make_pair(temp, strndup(path, MAX_PATH)));
2614
0
        if (total) *total += buf.st_size;
2615
0
      }
2616
2617
0
    } else if (entry->d_type & DT_DIR) {
2618
0
      if (strncmp(d_name, "..", 2) != 0 && strncmp(d_name, ".", 1) != 0) {
2619
0
        path_length = snprintf(path, MAX_PATH, "%s/%s", dir_name, d_name);
2620
2621
0
        if (path_length >= MAX_PATH) return false;
2622
2623
0
        scan_dir(path, dirlist, total);
2624
0
      }
2625
0
    }
2626
0
  }
2627
2628
0
  if (closedir(d)) return false;
2629
2630
0
  return true;
2631
0
}
2632
2633
/* **************************************** */
2634
2635
bool file_mtime_compare(const pair<struct dirent *, char *> &d1,
2636
0
                        const pair<struct dirent *, char *> &d2) {
2637
0
  struct stat sa, sb;
2638
2639
0
  if (!d1.second || !d2.second) return false;
2640
2641
0
  if (stat(d1.second, &sa) || stat(d2.second, &sb)) return false;
2642
2643
0
  return difftime(sa.st_mtime, sb.st_mtime) <= 0;
2644
0
}
2645
2646
/* **************************************** */
2647
2648
bool Utils::discardOldFilesExceeding(const char *path,
2649
0
                                     const unsigned long max_size) {
2650
0
  unsigned long total = 0;
2651
0
  list<pair<struct dirent *, char *> > fileslist;
2652
0
  list<pair<struct dirent *, char *> >::iterator it;
2653
0
  struct stat st;
2654
2655
0
  if (path == NULL || !strncmp(path, "", MAX_PATH)) return false;
2656
2657
  /* First, get a list of all non-dir dirents and compute total size */
2658
0
  if (!scan_dir(path, &fileslist, &total)) return false;
2659
2660
  // printf("path: %s, total: %u, max_size: %u\n", path, total, max_size);
2661
2662
0
  if (total < max_size) return true;
2663
2664
0
  fileslist.sort(file_mtime_compare);
2665
2666
  /* Third, traverse list and delete until we go below quota */
2667
0
  for (it = fileslist.begin(); it != fileslist.end(); ++it) {
2668
    // printf("[file: %s][path: %s]\n", it->first->d_name, it->second);
2669
0
    if (!it->second) continue;
2670
2671
0
    stat(it->second, &st);
2672
0
    unlink(it->second);
2673
2674
0
    total -= st.st_size;
2675
0
    if (total < max_size) break;
2676
0
  }
2677
2678
0
  for (it = fileslist.begin(); it != fileslist.end(); ++it) {
2679
0
    if (it->first) free(it->first);
2680
0
    if (it->second) free(it->second);
2681
0
  }
2682
2683
0
  return true;
2684
0
}
2685
2686
/* **************************************** */
2687
2688
137k
char *Utils::formatMac(const u_int8_t *const mac, char *buf, u_int buf_len) {
2689
137k
  if ((mac == NULL) || (ntop->getPrefs()->getHostMask() != no_host_mask))
2690
0
    snprintf(buf, buf_len, "00:00:00:00:00:00");
2691
137k
  else
2692
137k
    snprintf(buf, buf_len, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0] & 0xFF,
2693
137k
             mac[1] & 0xFF, mac[2] & 0xFF, mac[3] & 0xFF, mac[4] & 0xFF,
2694
137k
             mac[5] & 0xFF);
2695
137k
  return (buf);
2696
137k
}
2697
2698
/* **************************************** */
2699
2700
0
u_int64_t Utils::macaddr_int(const u_int8_t *mac) {
2701
0
  if (mac == NULL)
2702
0
    return (0);
2703
0
  else {
2704
0
    u_int64_t mac_int = 0;
2705
2706
0
    for (u_int8_t i = 0; i < 6; i++) {
2707
0
      mac_int |= ((u_int64_t)(mac[i] & 0xFF)) << (5 - i) * 8;
2708
0
    }
2709
2710
0
    return mac_int;
2711
0
  }
2712
0
}
2713
2714
/* **************************************** */
2715
2716
0
void Utils::readMac(const char *_ifname, dump_mac_t mac_addr) {
2717
0
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
2718
0
  char ifname[15];
2719
0
  macstr_t mac_addr_buf;
2720
0
  int res;
2721
2722
0
  ifname2devname(_ifname, ifname, sizeof(ifname));
2723
2724
#if defined(__FreeBSD__) || defined(__APPLE__)
2725
  struct ifaddrs *ifap, *ifaptr;
2726
  unsigned char *ptr;
2727
2728
  if ((res = getifaddrs(&ifap)) == 0) {
2729
    for (ifaptr = ifap; ifaptr != NULL; ifaptr = ifaptr->ifa_next) {
2730
      if (!strcmp(ifaptr->ifa_name, ifname) &&
2731
          (ifaptr->ifa_addr->sa_family == AF_LINK)) {
2732
        ptr = (unsigned char *)LLADDR((struct sockaddr_dl *)ifaptr->ifa_addr);
2733
        memcpy(mac_addr, ptr, 6);
2734
2735
        break;
2736
      }
2737
    }
2738
    freeifaddrs(ifap);
2739
  }
2740
#else
2741
0
  int _sock;
2742
0
  struct ifreq ifr;
2743
2744
0
  memset(&ifr, 0, sizeof(struct ifreq));
2745
2746
  /* Dummy socket, just to make ioctls with */
2747
0
  _sock = Utils::openSocket(PF_INET, SOCK_DGRAM, 0, "readMac");
2748
0
  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
2749
2750
0
  if ((res = ioctl(_sock, SIOCGIFHWADDR, &ifr)) >= 0)
2751
0
    memcpy(mac_addr, ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);
2752
2753
0
  Utils::closeSocket(_sock);
2754
0
#endif
2755
2756
0
  if (res < 0)
2757
0
    ntop->getTrace()->traceEvent(TRACE_ERROR, "Cannot get hw addr for %s",
2758
0
                                 ifname);
2759
0
  else
2760
0
    ntop->getTrace()->traceEvent(
2761
0
        TRACE_INFO, "Interface %s has MAC %s", ifname,
2762
0
        formatMac((u_int8_t *)mac_addr, mac_addr_buf, sizeof(mac_addr_buf)));
2763
#else
2764
  char ebuf[PCAP_ERRBUF_SIZE];
2765
  pcap_if_t *pdevs, *pdev;
2766
  bool found = false;
2767
  
2768
  memset(mac_addr, 0, 6);
2769
  
2770
  if (pcap_findalldevs(&pdevs, ebuf) == 0) {
2771
    pdev = pdevs;
2772
    while (pdev != NULL) {
2773
      if (Utils::validInterface(pdev) && Utils::isInterfaceUp(pdev->name)) {        
2774
  if (strstr(pdev->name, _ifname) != NULL) {
2775
    memcpy(mac_addr, pdev->addresses->addr->sa_data, 6);
2776
    break;
2777
  }
2778
      }
2779
      pdev = pdev->next;
2780
    }
2781
    
2782
    pcap_freealldevs(pdevs);
2783
  }
2784
#endif
2785
0
}
2786
2787
/* **************************************** */
2788
2789
6
u_int32_t Utils::readIPv4(char *ifname) {
2790
6
  u_int32_t ret_ip = 0;
2791
2792
6
#ifndef WIN32
2793
6
  struct ifreq ifr;
2794
6
  int fd;
2795
2796
6
  memset(&ifr, 0, sizeof(ifr));
2797
6
  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
2798
6
  ifr.ifr_addr.sa_family = AF_INET;
2799
2800
6
  if ((fd = Utils::openSocket(AF_INET, SOCK_DGRAM, IPPROTO_IP, "readIPv4")) <
2801
6
      0) {
2802
0
    ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to create socket");
2803
6
  } else {
2804
6
    if (ioctl(fd, SIOCGIFADDR, &ifr) == -1)
2805
2
      ntop->getTrace()->traceEvent(TRACE_INFO,
2806
2
                                   "Unable to read IPv4 for device %s", ifname);
2807
4
    else
2808
4
      ret_ip = (((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr).s_addr;
2809
2810
6
    Utils::closeSocket(fd);
2811
6
  }
2812
6
#endif
2813
2814
6
  return (ret_ip);
2815
6
}
2816
2817
/* **************************************** */
2818
2819
0
bool Utils::readIPv6(char *ifname, struct in6_addr *sin) {
2820
0
  bool rc = false;
2821
0
#ifdef __linux__
2822
0
  FILE *f;
2823
0
  int scope, prefix;
2824
0
  unsigned char ipv6[16];
2825
0
  char dname[IFNAMSIZ];
2826
2827
0
  f = fopen("/proc/net/if_inet6", "r");
2828
0
  if (f == NULL) return (false);
2829
2830
0
  while (19 == fscanf(f,
2831
0
                      " %2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%"
2832
0
                      "2hhx%2hhx%2hhx%2hhx%2hhx%2hhx %*x %x %x %*x %s",
2833
0
                      &ipv6[0], &ipv6[1], &ipv6[2], &ipv6[3], &ipv6[4],
2834
0
                      &ipv6[5], &ipv6[6], &ipv6[7], &ipv6[8], &ipv6[9],
2835
0
                      &ipv6[10], &ipv6[11], &ipv6[12], &ipv6[13], &ipv6[14],
2836
0
                      &ipv6[15], &prefix, &scope, dname)) {
2837
0
    if (strcmp(ifname, dname) != 0) continue;
2838
2839
0
    if (scope == 0x0000U /* IPV6_ADDR_GLOBAL */) {
2840
0
      memcpy(sin, ipv6, sizeof(ipv6));
2841
0
      rc = true;
2842
0
      break;
2843
0
    }
2844
0
  }
2845
2846
0
  fclose(f);
2847
0
#endif
2848
2849
0
  return rc;
2850
0
}
2851
2852
/* **************************************** */
2853
2854
2
u_int16_t Utils::getIfMTU(const char *ifname) {
2855
#ifdef WIN32
2856
  return (CONST_DEFAULT_MAX_PACKET_SIZE);
2857
#else
2858
2
  struct ifreq ifr;
2859
2
  u_int32_t max_packet_size = CONST_DEFAULT_MAX_PACKET_SIZE; /* default */
2860
2
  int fd;
2861
2862
2
  memset(&ifr, 0, sizeof(ifr));
2863
2
  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
2864
2
  ifr.ifr_addr.sa_family = AF_INET;
2865
2866
2
  if ((fd = Utils::openSocket(AF_INET, SOCK_DGRAM, 0, "getIfMTU")) < 0) {
2867
0
    ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to create socket");
2868
2
  } else {
2869
2
    if (ioctl(fd, SIOCGIFMTU, &ifr) == -1)
2870
2
      ntop->getTrace()->traceEvent(TRACE_INFO,
2871
2
                                   "Unable to read MTU for device %s", ifname);
2872
0
    else {
2873
0
      max_packet_size =
2874
0
          ifr.ifr_mtu + sizeof(struct ndpi_ethhdr) + sizeof(Ether80211q);
2875
2876
0
      if (max_packet_size > ((u_int16_t)-1)) max_packet_size = ((u_int16_t)-1);
2877
0
    }
2878
2879
2
    Utils::closeSocket(fd);
2880
2
  }
2881
2882
2
  return ((u_int16_t)max_packet_size);
2883
2
#endif
2884
2
}
2885
2886
/* **************************************** */
2887
2888
2
u_int32_t Utils::getMaxIfSpeed(const char *_ifname) {
2889
2
#if defined(__linux__) && \
2890
2
    (!defined(__GNUC_RH_RELEASE__) || (__GNUC_RH_RELEASE__ != 44))
2891
2
  int sock, rc;
2892
2
  struct ifreq ifr;
2893
2
  struct ethtool_cmd edata;
2894
2
  u_int32_t ifSpeed = 1000;
2895
2
  char ifname[15];
2896
2897
2
  if (strchr(_ifname, ',')) {
2898
    /* These are interfaces with , (e.g. eth0,eth1) */
2899
0
    char ifaces[128], *iface, *tmp;
2900
0
    u_int32_t speed = 0;
2901
2902
0
    snprintf(ifaces, sizeof(ifaces), "%s", _ifname);
2903
0
    iface = strtok_r(ifaces, ",", &tmp);
2904
2905
0
    while (iface) {
2906
0
      u_int32_t thisSpeed;
2907
2908
0
      ifname2devname(iface, ifname, sizeof(ifname));
2909
2910
0
      thisSpeed = getMaxIfSpeed(ifname);
2911
0
      if (thisSpeed > speed) speed = thisSpeed;
2912
2913
0
      iface = strtok_r(NULL, ",", &tmp);
2914
0
    }
2915
2916
0
    return (speed);
2917
2
  } else {
2918
2
    ifname2devname(_ifname, ifname, sizeof(ifname));
2919
2
  }
2920
2921
2
  memset(&ifr, 0, sizeof(struct ifreq));
2922
2923
2
  sock = Utils::openSocket(PF_INET, SOCK_DGRAM, 0, "getMaxIfSpeed");
2924
2
  if (sock < 0) {
2925
    // ntop->getTrace()->traceEvent(TRACE_ERROR, "Socket error [%s]", ifname);
2926
0
    return (ifSpeed);
2927
0
  }
2928
2929
2
  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
2930
2
  ifr.ifr_data = (char *)&edata;
2931
2932
  // Do the work
2933
2
  edata.cmd = ETHTOOL_GSET;
2934
2935
2
  rc = ioctl(sock, SIOCETHTOOL, &ifr);
2936
2
  Utils::closeSocket(sock);
2937
2938
2
  if (rc < 0) {
2939
    // ntop->getTrace()->traceEvent(TRACE_ERROR, "I/O Control error [%s]",
2940
    // ifname);
2941
2
    return (ifSpeed);
2942
2
  }
2943
2944
0
  if ((int32_t)ethtool_cmd_speed(&edata) != SPEED_UNKNOWN)
2945
0
    ifSpeed = ethtool_cmd_speed(&edata);
2946
2947
0
  ntop->getTrace()->traceEvent(TRACE_INFO, "Interface %s has MAC Speed = %u",
2948
0
                               ifname, edata.speed);
2949
2950
0
  return (ifSpeed);
2951
#else
2952
  return (1000);
2953
#endif
2954
2
}
2955
2956
/* **************************************** */
2957
2958
10
int Utils::ethtoolGet(const char *ifname, int cmd, uint32_t *v) {
2959
10
#if defined(__linux__)
2960
10
  struct ifreq ifr;
2961
10
  struct ethtool_value ethv;
2962
10
  int fd;
2963
2964
10
  memset(&ifr, 0, sizeof(ifr));
2965
2966
10
  fd = Utils::openSocket(AF_INET, SOCK_DGRAM, 0, "ethtoolGet");
2967
2968
10
  if (fd == -1) return -1;
2969
2970
10
  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
2971
2972
10
  ethv.cmd = cmd;
2973
10
  ifr.ifr_data = (char *)&ethv;
2974
2975
10
  if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
2976
10
    Utils::closeSocket(fd);
2977
10
    return -1;
2978
10
  }
2979
2980
0
  *v = ethv.data;
2981
0
  Utils::closeSocket(fd);
2982
2983
0
  return 0;
2984
#else
2985
  return -1;
2986
#endif
2987
10
}
2988
2989
/* **************************************** */
2990
2991
0
int Utils::ethtoolSet(const char *ifname, int cmd, uint32_t v) {
2992
0
#if defined(__linux__)
2993
0
  struct ifreq ifr;
2994
0
  struct ethtool_value ethv;
2995
0
  int fd;
2996
2997
0
  memset(&ifr, 0, sizeof(ifr));
2998
2999
0
  fd = Utils::openSocket(AF_INET, SOCK_DGRAM, 0, "ethtoolSet");
3000
3001
0
  if (fd == -1) return -1;
3002
3003
0
  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
3004
3005
0
  ethv.cmd = cmd;
3006
0
  ethv.data = v;
3007
0
  ifr.ifr_data = (char *)&ethv;
3008
3009
0
  if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) {
3010
0
    Utils::closeSocket(fd);
3011
0
    return -1;
3012
0
  }
3013
3014
0
  Utils::closeSocket(fd);
3015
3016
0
  return 0;
3017
#else
3018
  return -1;
3019
#endif
3020
0
}
3021
3022
/* **************************************** */
3023
3024
2
int Utils::disableOffloads(const char *ifname) {
3025
2
#if defined(__linux__)
3026
2
  uint32_t v = 0;
3027
3028
2
#ifdef ETHTOOL_GGRO
3029
2
  if (Utils::ethtoolGet(ifname, ETHTOOL_GGRO, &v) == 0 && v != 0)
3030
0
    Utils::ethtoolSet(ifname, ETHTOOL_SGRO, 0);
3031
2
#endif
3032
3033
2
#ifdef ETHTOOL_GGSO
3034
2
  if (Utils::ethtoolGet(ifname, ETHTOOL_GGSO, &v) == 0 && v != 0)
3035
0
    Utils::ethtoolSet(ifname, ETHTOOL_SGSO, 0);
3036
2
#endif
3037
3038
2
#ifdef ETHTOOL_GTSO
3039
2
  if (Utils::ethtoolGet(ifname, ETHTOOL_GTSO, &v) == 0 && v != 0)
3040
0
    Utils::ethtoolSet(ifname, ETHTOOL_STSO, 0);
3041
2
#endif
3042
3043
2
#ifdef ETHTOOL_GSG
3044
2
  if (Utils::ethtoolGet(ifname, ETHTOOL_GSG, &v) == 0 && v != 0)
3045
0
    Utils::ethtoolSet(ifname, ETHTOOL_SSG, 0);
3046
2
#endif
3047
3048
2
#ifdef ETHTOOL_GFLAGS
3049
2
  if (Utils::ethtoolGet(ifname, ETHTOOL_GFLAGS, &v) == 0 && (v & ETH_FLAG_LRO))
3050
0
    Utils::ethtoolSet(ifname, ETHTOOL_SFLAGS, v & ~ETH_FLAG_LRO);
3051
2
#endif
3052
3053
2
  return 0;
3054
#else
3055
  return -1;
3056
#endif
3057
2
}
3058
3059
/* **************************************** */
3060
3061
0
bool Utils::isGoodNameToCategorize(char *name) {
3062
0
  if ((name[0] == '\0') || (strchr(name, '.') == NULL) /* Missing domain */
3063
0
      || (!strcmp(name, "Broadcast")) || (!strcmp(name, "localhost")) ||
3064
0
      strchr((const char *)name, ':') /* IPv6 */
3065
0
      || (strstr(name, "in-addr.arpa")) || (strstr(name, "ip6.arpa")) ||
3066
0
      (strstr(name, "_dns-sd._udp")))
3067
0
    return (false);
3068
0
  else
3069
0
    return (true);
3070
0
}
3071
3072
/* **************************************** */
3073
3074
0
char *Utils::get2ndLevelDomain(char *_domainname) {
3075
0
  int i, found = 0;
3076
3077
0
  for (i = (int)strlen(_domainname) - 1, found = 0; (found != 2) && (i > 0);
3078
0
       i--) {
3079
0
    if (_domainname[i] == '.') {
3080
0
      found++;
3081
3082
0
      if (found == 2) {
3083
0
        return (&_domainname[i + 1]);
3084
0
      }
3085
0
    }
3086
0
  }
3087
3088
0
  return (_domainname);
3089
0
}
3090
3091
/* ****************************************************** */
3092
3093
0
char *Utils::tokenizer(char *arg, int c, char **data) {
3094
0
  char *p = NULL;
3095
3096
0
  if ((p = strchr(arg, c)) != NULL) {
3097
0
    *p = '\0';
3098
0
    if (data) {
3099
0
      if (strlen(arg))
3100
0
        *data = strdup(arg);
3101
0
      else
3102
0
        *data = strdup("");
3103
0
    }
3104
3105
0
    arg = &(p[1]);
3106
0
  } else if (data) {
3107
0
    if (arg)
3108
0
      *data = strdup(arg);
3109
0
    else
3110
0
      *data = NULL;
3111
0
  }
3112
3113
0
  return (arg);
3114
0
}
3115
3116
/* ****************************************************** */
3117
3118
0
in_addr_t Utils::inet_addr(const char *cp) {
3119
0
  if ((cp == NULL) || (cp[0] == '\0'))
3120
0
    return (0);
3121
0
  else
3122
0
    return (::inet_addr(cp));
3123
0
}
3124
3125
/* ****************************************************** */
3126
3127
211k
char *Utils::intoaV4(unsigned int addr, char *buf, u_short bufLen) {
3128
211k
  char *cp;
3129
211k
  int n;
3130
3131
211k
  cp = &buf[bufLen];
3132
211k
  *--cp = '\0';
3133
3134
211k
  n = 4;
3135
845k
  do {
3136
845k
    u_int byte = addr & 0xff;
3137
3138
845k
    *--cp = byte % 10 + '0';
3139
845k
    byte /= 10;
3140
845k
    if (byte > 0) {
3141
494k
      *--cp = byte % 10 + '0';
3142
494k
      byte /= 10;
3143
494k
      if (byte > 0) *--cp = byte + '0';
3144
494k
    }
3145
845k
    if (n > 1) *--cp = '.';
3146
845k
    addr >>= 8;
3147
845k
  } while (--n > 0);
3148
3149
211k
  return (cp);
3150
211k
}
3151
3152
/* ****************************************************** */
3153
3154
char *Utils::intoaV6(struct ndpi_in6_addr ipv6, u_int8_t bitmask, char *buf,
3155
14.8k
                     u_short bufLen) {
3156
14.8k
  char *ret;
3157
3158
252k
  for (int32_t i = bitmask, j = 0; i > 0; i -= 8, ++j)
3159
237k
    ipv6.u6_addr.u6_addr8[j] &=
3160
237k
        i >= 8 ? 0xff : (u_int32_t)((0xffU << (8 - i)) & 0xffU);
3161
3162
14.8k
  ret = (char *)inet_ntop(AF_INET6, &ipv6, buf, bufLen);
3163
3164
14.8k
  if (ret == NULL) {
3165
    /* Internal error (buffer too short) */
3166
0
    buf[0] = '\0';
3167
0
    return (buf);
3168
0
  } else
3169
14.8k
    return (ret);
3170
14.8k
}
3171
3172
/* ****************************************************** */
3173
3174
0
void Utils::xor_encdec(u_char *data, int data_len, u_char *key) {
3175
0
  int i, y;
3176
3177
0
  for (i = 0, y = 0; i < data_len; i++) {
3178
0
    data[i] ^= key[y++];
3179
0
    if (key[y] == 0) y = 0;
3180
0
  }
3181
0
}
3182
3183
/* ****************************************************** */
3184
3185
708k
u_int32_t Utils::macHash(const u_int8_t *const mac) {
3186
708k
  if (mac == NULL)
3187
0
    return (0);
3188
708k
  else {
3189
708k
    u_int32_t hash = 0;
3190
3191
4.95M
    for (int i = 0; i < 6; i++) hash += mac[i] << (i + 1);
3192
3193
708k
    return (hash);
3194
708k
  }
3195
708k
}
3196
3197
/* ****************************************************** */
3198
3199
80.5k
bool Utils::isEmptyMac(const u_int8_t *const mac) {
3200
80.5k
  static const u_int8_t zero[6] = {0, 0, 0, 0, 0, 0};
3201
3202
80.5k
  return (memcmp(mac, zero, 6) == 0);
3203
80.5k
}
3204
3205
/* ****************************************************** */
3206
3207
/* https://en.wikipedia.org/wiki/Multicast_address */
3208
/* https://hwaddress.com/company/private */
3209
80.2k
bool Utils::isSpecialMac(u_int8_t *mac) {
3210
80.2k
  if (isEmptyMac(mac))
3211
10.2k
    return (true);
3212
70.0k
  else {
3213
70.0k
    u_int16_t v2 = (mac[0] << 8) + mac[1];
3214
70.0k
    u_int32_t v3 = (mac[0] << 16) + (mac[1] << 8) + mac[2];
3215
3216
70.0k
    switch (v3) {
3217
51
      case 0x01000C:
3218
64
      case 0x0180C2:
3219
567
      case 0x01005E:
3220
578
      case 0x010CCD:
3221
588
      case 0x011B19:
3222
614
      case 0x00006C:
3223
656
      case 0x000101:
3224
662
      case 0x000578:
3225
673
      case 0x000B18:
3226
684
      case 0x000BF4:
3227
696
      case 0x000C53:
3228
706
      case 0x000D58:
3229
716
      case 0x000DA7:
3230
731
      case 0x000DC2:
3231
741
      case 0x000DF2:
3232
751
      case 0x000E17:
3233
765
      case 0x000E22:
3234
775
      case 0x000E2A:
3235
785
      case 0x000EEF:
3236
801
      case 0x000F09:
3237
813
      case 0x0016B4:
3238
823
      case 0x001761:
3239
835
      case 0x001825:
3240
846
      case 0x002067:
3241
857
      case 0x00221C:
3242
870
      case 0x0022F1:
3243
881
      case 0x00234A:
3244
892
      case 0x00238C:
3245
903
      case 0x0023F7:
3246
913
      case 0x002419:
3247
925
      case 0x0024FB:
3248
935
      case 0x00259D:
3249
946
      case 0x0025DF:
3250
956
      case 0x00269F:
3251
967
      case 0x005047:
3252
971
      case 0x005079:
3253
981
      case 0x0050C2:
3254
997
      case 0x0050C7:
3255
1.01k
      case 0x0084ED:
3256
1.02k
      case 0x0086A0:
3257
1.03k
      case 0x00A054:
3258
1.04k
      case 0x00A085:
3259
1.05k
      case 0x00CB00:
3260
1.06k
      case 0x0418B6:
3261
1.07k
      case 0x0C8112:
3262
1.12k
      case 0x100000:
3263
1.13k
      case 0x10AE60:
3264
1.14k
      case 0x10B713:
3265
1.15k
      case 0x1100AA:
3266
1.17k
      case 0x111111:
3267
1.18k
      case 0x140708:
3268
1.19k
      case 0x146E0A:
3269
1.21k
      case 0x18421D:
3270
1.22k
      case 0x1CF4CA:
3271
1.23k
      case 0x205B2A:
3272
1.24k
      case 0x20D160:
3273
1.25k
      case 0x24336C:
3274
1.26k
      case 0x24BF74:
3275
1.27k
      case 0x28EF01:
3276
1.28k
      case 0x3CB87A:
3277
1.29k
      case 0x40A93F:
3278
1.30k
      case 0x40D855:
3279
1.31k
      case 0x487604:
3280
1.32k
      case 0x48D35D:
3281
1.33k
      case 0x48F317:
3282
1.35k
      case 0x50E14A:
3283
1.36k
      case 0x544E45:
3284
1.37k
      case 0x580943:
3285
1.38k
      case 0x586ED6:
3286
1.39k
      case 0x604BAA:
3287
1.40k
      case 0x609620:
3288
1.41k
      case 0x68E166:
3289
1.42k
      case 0x706F81:
3290
1.44k
      case 0x78F944:
3291
1.45k
      case 0x7CE4AA:
3292
1.46k
      case 0x8C8401:
3293
1.47k
      case 0x8CE748:
3294
1.48k
      case 0x906F18:
3295
1.49k
      case 0x980EE4:
3296
1.51k
      case 0x9C93E4:
3297
1.52k
      case 0xA0D86F:
3298
1.53k
      case 0xA468BC:
3299
1.54k
      case 0xA4A6A9:
3300
1.55k
      case 0xACDE48:
3301
1.57k
      case 0xACF85C:
3302
1.58k
      case 0xB025AA:
3303
1.59k
      case 0xB0ECE1:
3304
1.60k
      case 0xB0FEBD:
3305
1.61k
      case 0xB4E1EB:
3306
1.61k
      case 0xC02250:
3307
1.62k
      case 0xC8AACC:
3308
1.63k
      case 0xCC3ADF:
3309
1.64k
      case 0xD85DFB:
3310
1.65k
      case 0xDC7014:
3311
1.68k
      case 0xE0CB1D:
3312
1.68k
      case 0xE4F14C:
3313
1.70k
      case 0xE80410:
3314
1.71k
      case 0xE89E0C:
3315
1.72k
      case 0xF04F7C:
3316
1.73k
      case 0xF0A225:
3317
1.74k
      case 0xFCC233:
3318
1.74k
        return (true);
3319
70.0k
    }
3320
3321
68.2k
    switch (v2) {
3322
4.34k
      case 0xFFFF:
3323
4.82k
      case 0x3333:
3324
4.82k
        return (true);
3325
0
        break;
3326
68.2k
    }
3327
3328
63.4k
    return (false);
3329
68.2k
  }
3330
80.2k
}
3331
3332
/* ****************************************************** */
3333
3334
80.2k
bool Utils::isBroadcastMac(const u_int8_t *mac) {
3335
80.2k
  u_int8_t broad[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
3336
3337
80.2k
  return (memcmp(mac, broad, 6) == 0);
3338
80.2k
}
3339
3340
/* ****************************************************** */
3341
3342
/*
3343
  http://h22208.www2.hpe.com/eginfolib/networking/docs/switches/5130ei/5200-3944_ip-multi_cg/content/483573739.htm
3344
  https://ipcisco.com/lesson/multicast-mac-addresses/
3345
*/
3346
267
bool Utils::isMulticastMac(const u_int8_t *mac) {
3347
267
  if (isEmptyMac(mac)) return (false);
3348
3349
233
  if (((mac[0] == 0x33) && (mac[1] == 0x33)) ||
3350
233
      ((mac[0] == 0x01) && (mac[1] == 0x00) && (mac[2] == 0x5E)))
3351
60
    return (true);
3352
173
  else
3353
173
    return (false);
3354
233
}
3355
3356
/* ****************************************************** */
3357
3358
0
void Utils::parseMac(u_int8_t *mac, const char *symMac) {
3359
0
  int _mac[6] = {0};
3360
3361
0
  if (symMac)
3362
0
    sscanf(symMac, "%x:%x:%x:%x:%x:%x", &_mac[0], &_mac[1], &_mac[2], &_mac[3],
3363
0
           &_mac[4], &_mac[5]);
3364
3365
0
  for (int i = 0; i < 6; i++) mac[i] = (u_int8_t)_mac[i];
3366
0
}
3367
3368
/* *********************************************** */
3369
3370
ndpi_patricia_node_t *Utils::add_to_ptree(ndpi_patricia_tree_t *tree,
3371
57
                                          int family, void *addr, int bits) {
3372
57
  ndpi_prefix_t prefix;
3373
57
  ndpi_patricia_node_t *node;
3374
57
  u_int16_t maxbits = ndpi_patricia_get_maxbits(tree);
3375
3376
57
  if (family == AF_INET)
3377
55
    ndpi_fill_prefix_v4(&prefix, (struct in_addr *)addr, bits, maxbits);
3378
2
  else if (family == AF_INET6)
3379
2
    ndpi_fill_prefix_v6(&prefix, (struct in6_addr *)addr, bits, maxbits);
3380
0
  else
3381
0
    ndpi_fill_prefix_mac(&prefix, (u_int8_t *)addr, bits, maxbits);
3382
3383
57
  node = ndpi_patricia_lookup(tree, &prefix);
3384
3385
57
  return (node);
3386
57
}
3387
3388
/* ******************************************* */
3389
3390
ndpi_patricia_node_t *Utils::ptree_match(ndpi_patricia_tree_t *tree, int family,
3391
466k
                                         const void *const addr, int bits) {
3392
466k
  ndpi_prefix_t prefix;
3393
466k
  u_int16_t maxbits = ndpi_patricia_get_maxbits(tree);
3394
3395
466k
  if (addr == NULL) return (NULL);
3396
3397
466k
  if (family == AF_INET)
3398
426k
    ndpi_fill_prefix_v4(&prefix, (struct in_addr *)addr, bits, maxbits);
3399
39.7k
  else if (family == AF_INET6)
3400
39.7k
    ndpi_fill_prefix_v6(&prefix, (struct in6_addr *)addr, bits, maxbits);
3401
0
  else
3402
0
    ndpi_fill_prefix_mac(&prefix, (u_int8_t *)addr, bits, maxbits);
3403
3404
466k
  if (prefix.bitlen > maxbits) { /* safety check */
3405
0
    char buf[128];
3406
0
    ntop->getTrace()->traceEvent(
3407
0
        TRACE_ERROR,
3408
0
        "Bad radix tree lookup for %s "
3409
0
        "(prefix family = %u, len = %u (%u), tree max len = %u)",
3410
0
        Utils::ptree_prefix_print(&prefix, buf, sizeof(buf)) ? buf : "-",
3411
0
        family, prefix.bitlen, bits, maxbits);
3412
0
    return NULL;
3413
0
  }
3414
3415
466k
  return (ndpi_patricia_search_best(tree, &prefix));
3416
466k
}
3417
3418
/* ******************************************* */
3419
3420
ndpi_patricia_node_t *Utils::ptree_add_rule(ndpi_patricia_tree_t *ptree,
3421
4
                                            const char *addr_line) {
3422
4
  char *ip, *bits, *slash = NULL, *line = NULL;
3423
4
  struct in_addr addr4;
3424
4
  struct in6_addr addr6;
3425
4
  u_int8_t mac[6];
3426
4
  u_int32_t _mac[6];
3427
4
  ndpi_patricia_node_t *node = NULL;
3428
3429
4
  line = strdup(addr_line);
3430
4
  ip = line;
3431
4
  bits = strchr(line, '/');
3432
4
  if (bits == NULL)
3433
0
    bits = (char *)"/32";
3434
4
  else {
3435
4
    slash = bits;
3436
4
    slash[0] = '\0';
3437
4
  }
3438
3439
4
  bits++;
3440
3441
4
  ntop->getTrace()->traceEvent(TRACE_DEBUG, "Rule %s/%s", ip, bits);
3442
3443
4
  if (sscanf(ip, "%02X:%02X:%02X:%02X:%02X:%02X", &_mac[0], &_mac[1], &_mac[2],
3444
4
             &_mac[3], &_mac[4], &_mac[5]) == 6) {
3445
0
    for (int i = 0; i < 6; i++) mac[i] = _mac[i];
3446
0
    node = add_to_ptree(ptree, AF_MAC, mac, 48);
3447
4
  } else if (strchr(ip, ':') != NULL) { /* IPv6 */
3448
2
    if (inet_pton(AF_INET6, ip, &addr6) == 1)
3449
2
      node = add_to_ptree(ptree, AF_INET6, &addr6, atoi(bits));
3450
0
    else
3451
0
      ntop->getTrace()->traceEvent(TRACE_ERROR, "Error parsing IPv6 %s\n", ip);
3452
2
  } else { /* IPv4 */
3453
    /* inet_aton(ip, &addr4) fails parsing subnets */
3454
2
    int num_octets;
3455
2
    u_int ip4_0 = 0, ip4_1 = 0, ip4_2 = 0, ip4_3 = 0;
3456
2
    u_char *ip4 = (u_char *)&addr4;
3457
3458
2
    if ((num_octets =
3459
2
             sscanf(ip, "%u.%u.%u.%u", &ip4_0, &ip4_1, &ip4_2, &ip4_3)) >= 1) {
3460
2
      int num_bits = atoi(bits);
3461
3462
2
      ip4[0] = ip4_0, ip4[1] = ip4_1, ip4[2] = ip4_2, ip4[3] = ip4_3;
3463
3464
2
      if (num_bits > 32) num_bits = 32;
3465
3466
2
      if (num_octets * 8 < num_bits)
3467
0
        ntop->getTrace()->traceEvent(
3468
0
            TRACE_INFO, "Found IP smaller than netmask [%s]", line);
3469
3470
      // addr4.s_addr = ntohl(addr4.s_addr);
3471
2
      node = add_to_ptree(ptree, AF_INET, &addr4, num_bits);
3472
2
    } else {
3473
0
      ntop->getTrace()->traceEvent(TRACE_ERROR, "Error parsing IPv4 %s\n", ip);
3474
0
    }
3475
2
  }
3476
3477
  // ntop->getTrace()->traceEvent(TRACE_NORMAL, "Added IPv%d rule %s/%s [%p]",
3478
  // isV4 ? 4 : 6, ip, bits, node);
3479
3480
4
  if (line) free(line);
3481
4
  return (node);
3482
4
}
3483
3484
/* ******************************************* */
3485
3486
bool Utils::ptree_prefix_print(ndpi_prefix_t *prefix, char *buffer,
3487
0
                               size_t bufsize) {
3488
0
  char *a, ipbuf[64];
3489
3490
0
  switch (prefix->family) {
3491
0
    case AF_INET:
3492
0
      a = Utils::intoaV4(ntohl(prefix->add.sin.s_addr), ipbuf, sizeof(ipbuf));
3493
0
      snprintf(buffer, bufsize, "%s/%d", a, prefix->bitlen);
3494
0
      return (true);
3495
3496
0
    case AF_INET6:
3497
0
      a = Utils::intoaV6(*((struct ndpi_in6_addr *)&prefix->add.sin6),
3498
0
                         prefix->bitlen, ipbuf, sizeof(ipbuf));
3499
0
      snprintf(buffer, bufsize, "%s/%d", a, prefix->bitlen);
3500
0
      return (true);
3501
0
  }
3502
3503
0
  return (false);
3504
0
}
3505
3506
/* ******************************************* */
3507
3508
0
int Utils::numberOfSetBits(u_int32_t i) {
3509
  // Java: use >>> instead of >>
3510
  // C or C++: use uint32_t
3511
0
  i = i - ((i >> 1) & 0x55555555);
3512
0
  i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
3513
0
  return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
3514
0
}
3515
3516
/* ******************************************* */
3517
3518
void Utils::initRedis(Redis **r, const char *redis_host,
3519
                      const char *redis_password, u_int16_t redis_port,
3520
4
                      u_int8_t _redis_db_id, bool giveup_on_failure) {
3521
4
  if (r) {
3522
4
    if (*r) delete (*r);
3523
4
    (*r) = new (std::nothrow) Redis(redis_host, redis_password, redis_port,
3524
4
                                    _redis_db_id, giveup_on_failure);
3525
4
  }
3526
4
}
3527
3528
/* ******************************************* */
3529
3530
0
int Utils::tcpStateStr2State(const char *state_str) {
3531
0
  map<string, int>::const_iterator it;
3532
3533
0
  if ((it = tcp_state_str_2_state.find(state_str)) !=
3534
0
      tcp_state_str_2_state.end())
3535
0
    return it->second;
3536
3537
0
  return 0;
3538
0
}
3539
3540
/* ******************************************* */
3541
3542
0
const char *Utils::tcpState2StateStr(int state) {
3543
0
  map<int, string>::const_iterator it;
3544
3545
0
  if ((it = tcp_state_2_state_str.find(state)) != tcp_state_2_state_str.end())
3546
0
    return it->second.c_str();
3547
3548
0
  return "UNKNOWN";
3549
0
}
3550
3551
/* ******************************************* */
3552
3553
0
eBPFEventType Utils::eBPFEventStr2Event(const char *event_str) {
3554
0
  map<string, eBPFEventType>::const_iterator it;
3555
3556
0
  if ((it = ebpf_event_str_2_event.find(event_str)) !=
3557
0
      ebpf_event_str_2_event.end())
3558
0
    return it->second;
3559
3560
0
  return ebpf_event_type_unknown;
3561
0
}
3562
3563
/* ******************************************* */
3564
3565
0
const char *Utils::eBPFEvent2EventStr(eBPFEventType event) {
3566
0
  map<eBPFEventType, string>::const_iterator it;
3567
3568
0
  if ((it = ebpf_event_2_event_str.find(event)) != ebpf_event_2_event_str.end())
3569
0
    return it->second.c_str();
3570
3571
0
  return "UNKNOWN";
3572
0
}
3573
3574
/* ******************************************* */
3575
3576
/*
3577
  IMPORTANT: line buffer is large enough to contain the replaced string
3578
*/
3579
0
void Utils::replacestr(char *line, const char *search, const char *replace) {
3580
0
  char *sp;
3581
0
  int search_len, replace_len, tail_len;
3582
3583
0
  if ((sp = strstr(line, search)) == NULL) {
3584
0
    return;
3585
0
  }
3586
3587
0
  search_len = strlen(search), replace_len = strlen(replace);
3588
0
  tail_len = strlen(sp + search_len);
3589
3590
0
  memmove(sp + replace_len, sp + search_len, tail_len + 1);
3591
0
  memcpy(sp, replace, replace_len);
3592
0
}
3593
3594
/* ****************************************************** */
3595
3596
0
u_int32_t Utils::stringHash(const char *s) {
3597
0
  u_int32_t hash = 0;
3598
0
  const char *p = s;
3599
0
  int pos = 0;
3600
3601
0
  while (*p) {
3602
0
    hash += (*p) << pos;
3603
0
    p++;
3604
0
    pos += 8;
3605
0
    if (pos == 32) pos = 0;
3606
0
  }
3607
3608
0
  return hash;
3609
0
}
3610
3611
/* ****************************************************** */
3612
3613
/* Note: the returned IP address is in network byte order */
3614
0
u_int32_t Utils::getHostManagementIPv4Address() {
3615
0
  int sock =
3616
0
      Utils::openSocket(AF_INET, SOCK_DGRAM, 0, "getHostManagementIPv4Address");
3617
0
  const char *kGoogleDnsIp = "8.8.8.8";
3618
0
  u_int16_t kDnsPort = 53;
3619
0
  struct sockaddr_in serv;
3620
0
  struct sockaddr_in name;
3621
0
  socklen_t namelen = sizeof(name);
3622
0
  u_int32_t me;
3623
3624
0
  memset(&serv, 0, sizeof(serv));
3625
0
  serv.sin_family = AF_INET;
3626
0
  serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp);
3627
0
  serv.sin_port = htons(kDnsPort);
3628
3629
0
  if ((connect(sock, (const struct sockaddr *)&serv, sizeof(serv)) == 0) &&
3630
0
      (getsockname(sock, (struct sockaddr *)&name, &namelen) == 0)) {
3631
0
    me = name.sin_addr.s_addr;
3632
0
  } else
3633
0
    me = inet_addr("127.0.0.1");
3634
3635
0
  Utils::closeSocket(sock);
3636
3637
0
  return (me);
3638
0
}
3639
3640
/* ****************************************************** */
3641
3642
20
bool Utils::isInterfaceUp(char *_ifname) {
3643
#ifdef WIN32
3644
  return (true);
3645
#else
3646
20
  char ifname[IFNAMSIZ];
3647
20
  struct ifreq ifr;
3648
20
  int sock;
3649
3650
20
  sock = Utils::openSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP, "isInterfaceUp");
3651
3652
20
  if (sock == -1) return (false);
3653
3654
20
  ifname2devname(_ifname, ifname, sizeof(ifname));
3655
3656
20
  memset(&ifr, 0, sizeof(ifr));
3657
20
  strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
3658
3659
20
  if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
3660
12
    Utils::closeSocket(sock);
3661
12
    return (false);
3662
12
  }
3663
3664
8
  Utils::closeSocket(sock);
3665
3666
8
  return (!!(ifr.ifr_flags & IFF_UP) ? true : false);
3667
20
#endif
3668
20
}
3669
3670
/* ****************************************************** */
3671
3672
482
bool Utils::maskHost(bool isLocalIP) {
3673
482
  bool mask_host = false;
3674
3675
482
  switch (ntop->getPrefs()->getHostMask()) {
3676
0
    case mask_local_hosts:
3677
0
      if (isLocalIP) mask_host = true;
3678
0
      break;
3679
3680
0
    case mask_remote_hosts:
3681
0
      if (!isLocalIP) mask_host = true;
3682
0
      break;
3683
3684
482
    default:
3685
482
      break;
3686
482
  }
3687
3688
482
  return (mask_host);
3689
482
}
3690
3691
/* ****************************************************** */
3692
3693
0
bool Utils::getCPULoad(cpu_load_stats *out) {
3694
0
#if !defined(__FreeBSD__) && !defined(__NetBSD__) & !defined(__OpenBSD__) && \
3695
0
    !defined(__APPLE__) && !defined(WIN32)
3696
0
  float load;
3697
0
  FILE *fp;
3698
3699
0
  if ((fp = fopen("/proc/loadavg", "r"))) {
3700
0
    if (fscanf(fp, "%f", &load) != 1) load = 0;
3701
0
    fclose(fp);
3702
3703
0
    out->load = load;
3704
3705
0
    return (true);
3706
0
  }
3707
0
#endif
3708
3709
0
  return (false);
3710
0
};
3711
3712
/* ****************************************************** */
3713
3714
0
void Utils::luaMeminfo(lua_State *vm) {
3715
0
#if !defined(__FreeBSD__) && !defined(__NetBSD__) & !defined(__OpenBSD__) && \
3716
0
    !defined(__APPLE__) && !defined(WIN32)
3717
0
  long unsigned int memtotal = 0, memfree = 0, buffers = 0, cached = 0,
3718
0
                    sreclaimable = 0, shmem = 0;
3719
0
  long unsigned int mem_resident = 0, mem_virtual = 0;
3720
0
  char *line = NULL;
3721
0
  size_t len;
3722
0
  int read;
3723
0
  FILE *fp;
3724
3725
0
  if (vm) {
3726
0
    if ((fp = fopen("/proc/meminfo", "r"))) {
3727
0
      while ((read = getline(&line, &len, fp)) != -1) {
3728
0
        if (!strncmp(line, "MemTotal", strlen("MemTotal")) &&
3729
0
            sscanf(line, "%*s %lu kB", &memtotal))
3730
0
          lua_push_uint64_table_entry(vm, "mem_total", memtotal);
3731
0
        else if (!strncmp(line, "MemFree", strlen("MemFree")) &&
3732
0
                 sscanf(line, "%*s %lu kB", &memfree))
3733
0
          lua_push_uint64_table_entry(vm, "mem_free", memfree);
3734
0
        else if (!strncmp(line, "Buffers", strlen("Buffers")) &&
3735
0
                 sscanf(line, "%*s %lu kB", &buffers))
3736
0
          lua_push_uint64_table_entry(vm, "mem_buffers", buffers);
3737
0
        else if (!strncmp(line, "Cached", strlen("Cached")) &&
3738
0
                 sscanf(line, "%*s %lu kB", &cached))
3739
0
          lua_push_uint64_table_entry(vm, "mem_cached", cached);
3740
0
        else if (!strncmp(line, "SReclaimable", strlen("SReclaimable")) &&
3741
0
                 sscanf(line, "%*s %lu kB", &sreclaimable))
3742
0
          lua_push_uint64_table_entry(vm, "mem_sreclaimable", sreclaimable);
3743
0
        else if (!strncmp(line, "Shmem", strlen("Shmem")) &&
3744
0
                 sscanf(line, "%*s %lu kB", &shmem))
3745
0
          lua_push_uint64_table_entry(vm, "mem_shmem", shmem);
3746
0
      }
3747
3748
0
      if (line) {
3749
0
        free(line);
3750
0
        line = NULL;
3751
0
      }
3752
3753
0
      fclose(fp);
3754
3755
      /* Equivalent to top utility mem used */
3756
0
      lua_push_uint64_table_entry(
3757
0
          vm, "mem_used",
3758
0
          memtotal - memfree - (buffers + cached + sreclaimable - shmem));
3759
0
    }
3760
3761
0
    if ((fp = fopen("/proc/self/status", "r"))) {
3762
0
      while ((read = getline(&line, &len, fp)) != -1) {
3763
0
        if (!strncmp(line, "VmRSS", strlen("VmRSS")) &&
3764
0
            sscanf(line, "%*s %lu kB", &mem_resident))
3765
0
          lua_push_uint64_table_entry(vm, "mem_ntopng_resident", mem_resident);
3766
0
        else if (!strncmp(line, "VmSize", strlen("VmSize")) &&
3767
0
                 sscanf(line, "%*s %lu kB", &mem_virtual))
3768
0
          lua_push_uint64_table_entry(vm, "mem_ntopng_virtual", mem_virtual);
3769
0
      }
3770
3771
0
      if (line) {
3772
0
        free(line);
3773
0
        line = NULL;
3774
0
      }
3775
3776
0
      fclose(fp);
3777
0
    }
3778
0
  }
3779
0
#endif
3780
0
};
3781
3782
/* ****************************************************** */
3783
3784
2
char *Utils::getInterfaceDescription(char *ifname, char *buf, int buf_len) {
3785
2
  ntop_if_t *devpointer, *cur;
3786
3787
2
  snprintf(buf, buf_len, "%s", ifname);
3788
3789
2
  if (!Utils::ntop_findalldevs(&devpointer)) {
3790
6
    for (cur = devpointer; cur; cur = cur->next) {
3791
4
      if (strcmp(cur->name, ifname) == 0) {
3792
0
        if (cur->description && cur->description[0])
3793
0
          snprintf(buf, buf_len, "%s", cur->description);
3794
0
        break;
3795
0
      }
3796
4
    }
3797
3798
2
    Utils::ntop_freealldevs(devpointer);
3799
2
  }
3800
3801
2
  return (buf);
3802
2
}
3803
3804
/* ****************************************************** */
3805
3806
0
int Utils::bindSockToDevice(int sock, int family, const char *devicename) {
3807
#ifdef WIN32
3808
  return (0);
3809
#else
3810
0
  struct ifaddrs *pList = NULL;
3811
0
  struct ifaddrs *pAdapter = NULL;
3812
0
  struct ifaddrs *pAdapterFound = NULL;
3813
0
  int bindresult = -1;
3814
3815
0
  int result = getifaddrs(&pList);
3816
3817
0
  if (result < 0) return -1;
3818
3819
0
  pAdapter = pList;
3820
0
  while (pAdapter) {
3821
0
    if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_name != NULL) &&
3822
0
        (family == pAdapter->ifa_addr->sa_family)) {
3823
0
      if (strcmp(pAdapter->ifa_name, devicename) == 0) {
3824
0
        pAdapterFound = pAdapter;
3825
0
        break;
3826
0
      }
3827
0
    }
3828
3829
0
    pAdapter = pAdapter->ifa_next;
3830
0
  }
3831
3832
0
  if (pAdapterFound != NULL) {
3833
0
    int addrsize =
3834
0
        (family == AF_INET6) ? sizeof(sockaddr_in6) : sizeof(sockaddr_in);
3835
0
    bindresult = ::bind(sock, pAdapterFound->ifa_addr, addrsize);
3836
0
  }
3837
3838
0
  freeifaddrs(pList);
3839
0
  return bindresult;
3840
0
#endif
3841
0
}
3842
3843
/* ****************************************************** */
3844
3845
0
int Utils::retainWriteCapabilities() {
3846
0
  int rc = 0;
3847
3848
#ifdef HAVE_LIBCAP
3849
  cap_t caps;
3850
3851
  /* Add the capability of interest to the permitted capabilities  */
3852
  caps = cap_get_proc();
3853
  if (cap_set_flag(caps, CAP_PERMITTED, num_cap, cap_values, CAP_SET) == -1)
3854
    ntop->getTrace()->traceEvent(
3855
        TRACE_WARNING, "Capabilities cap_set_flag error: %s", strerror(errno));
3856
3857
  if (cap_set_flag(caps, CAP_INHERITABLE, num_cap, cap_values, CAP_SET) == -1)
3858
    ntop->getTrace()->traceEvent(
3859
        TRACE_WARNING, "Capabilities cap_set_flag error: %s", strerror(errno));
3860
3861
  if (cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values, CAP_SET) == -1)
3862
    ntop->getTrace()->traceEvent(
3863
        TRACE_WARNING, "Capabilities cap_set_flag error: %s", strerror(errno));
3864
3865
  rc = cap_set_proc(caps);
3866
  if (rc == 0) {
3867
#ifdef TRACE_CEPABILITIES
3868
    ntop->getTrace()->traceEvent(
3869
        TRACE_NORMAL, "[CAPABILITIES] INITIAL SETUP [%s][num_cap: %u]",
3870
        cap_to_text(caps, NULL), num_cap);
3871
#endif
3872
3873
    /* Tell the kernel to retain permitted capabilities */
3874
    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
3875
      ntop->getTrace()->traceEvent(
3876
          TRACE_WARNING, "Unable to retain permitted capabilities [%s]\n",
3877
          strerror(errno));
3878
      rc = -1;
3879
    }
3880
  } else {
3881
    ntop->getTrace()->traceEvent(
3882
        TRACE_WARNING, "Capabilities cap_set_proc error: %s", strerror(errno));
3883
  }
3884
3885
  if (cap_free(caps) == -1)
3886
    ntop->getTrace()->traceEvent(
3887
        TRACE_WARNING, "Capabilities cap_free error: %s", strerror(errno));
3888
3889
#else
3890
0
#if !defined(__APPLE__) && !defined(__FreeBSD__)
3891
0
  rc = -1;
3892
0
  ntop->getTrace()->traceEvent(TRACE_WARNING,
3893
0
                               "ntopng has not been compiled with libcap-dev");
3894
0
  ntop->getTrace()->traceEvent(
3895
0
      TRACE_WARNING,
3896
0
      "Network discovery and other privileged activities will fail");
3897
0
#endif
3898
0
#endif
3899
3900
0
  return (rc);
3901
0
}
3902
3903
/* ****************************************************** */
3904
3905
#if !defined(__APPLE__) && !defined(__FreeBSD__)
3906
3907
static Mutex capabilitiesMutex;
3908
3909
0
static int _setWriteCapabilities(int enable) {
3910
0
  int rc = 0;
3911
3912
#ifdef HAVE_LIBCAP
3913
  cap_t caps;
3914
3915
  /*
3916
    NOTE
3917
3918
    The capabilitiesMutex lock is used to avoid that two threads concurrently
3919
    enable/disable capabilities
3920
   */
3921
  if (enable) capabilitiesMutex.lock(__FILE__, __LINE__);
3922
3923
  caps = cap_get_proc();
3924
  if (caps) {
3925
#ifdef TRACE_CEPABILITIES
3926
    ntop->getTrace()->traceEvent(TRACE_NORMAL,
3927
                                 "[CAPABILITIES] BEFORE [enable: %u][%s]",
3928
                                 enable, cap_to_text(caps, NULL));
3929
#endif
3930
3931
    if (cap_set_flag(caps, CAP_EFFECTIVE, num_cap, cap_values,
3932
                     enable ? CAP_SET : CAP_CLEAR) == -1)
3933
      ntop->getTrace()->traceEvent(TRACE_WARNING,
3934
                                   "Capabilities cap_set_flag error: %s",
3935
                                   strerror(errno));
3936
3937
    if (cap_set_proc(caps) == -1)
3938
      ntop->getTrace()->traceEvent(
3939
          TRACE_WARNING, "Capabilities cap_set_proc error: %s [enable: %u]",
3940
          strerror(errno), enable);
3941
    else {
3942
#ifdef TRACE_CEPABILITIES
3943
      ntop->getTrace()->traceEvent(TRACE_NORMAL,
3944
                                   "[CAPABILITIES] Capabilities %s [rc: %d]",
3945
                                   enable ? "ENABLE" : "DISABLE", rc);
3946
#endif
3947
    }
3948
3949
    if (cap_free(caps) == -1)
3950
      ntop->getTrace()->traceEvent(TRACE_WARNING,
3951
                                   "Capabilities cap_free error");
3952
  } else
3953
    rc = -1;
3954
3955
  if (!enable) capabilitiesMutex.unlock(__FILE__, __LINE__);
3956
#else
3957
0
  rc = -1;
3958
0
#endif
3959
3960
0
  return (rc);
3961
0
}
3962
#endif
3963
3964
/* ****************************************************** */
3965
3966
/*
3967
  Usage example
3968
3969
  local path="/etc/test.lua"
3970
3971
  ntop.gainWriteCapabilities()
3972
3973
  file = io.open(path, "w")
3974
  if(file ~= nil) then
3975
  file:write("-- End of the test.lua file")
3976
  file:close()
3977
  else
3978
  print("Unable to create file "..path.."<p>")
3979
  end
3980
3981
  ntop.dropWriteCapabilities()
3982
*/
3983
3984
0
int Utils::gainWriteCapabilities() {
3985
0
#if !defined(__APPLE__) && !defined(__FreeBSD__)
3986
0
  if (ntop && !ntop->hasDroppedPrivileges()) return (0);
3987
3988
0
  return (_setWriteCapabilities(true));
3989
#else
3990
  return (0);
3991
#endif
3992
0
}
3993
3994
/* ****************************************************** */
3995
3996
0
int Utils::dropWriteCapabilities() {
3997
0
#if !defined(__APPLE__) && !defined(__FreeBSD__)
3998
0
  if (ntop && !ntop->hasDroppedPrivileges()) return (0);
3999
4000
0
  return (_setWriteCapabilities(false));
4001
#else
4002
  return (0);
4003
#endif
4004
0
}
4005
4006
/* ******************************* */
4007
4008
/* Return IP is network byte order */
4009
0
u_int32_t Utils::findInterfaceGatewayIPv4(const char *ifname) {
4010
0
#ifndef WIN32
4011
0
  char cmd[128];
4012
0
  FILE *fp;
4013
4014
0
  snprintf(cmd, sizeof(cmd),
4015
0
           "netstat -rn | grep '%s' | grep 'UG' | awk '{print $2}'", ifname);
4016
4017
0
  if ((fp = popen(cmd, "r")) != NULL) {
4018
0
    char line[256];
4019
0
    u_int32_t rc = 0;
4020
4021
0
    if (fgets(line, sizeof(line), fp) != NULL) rc = inet_addr(line);
4022
4023
0
    pclose(fp);
4024
0
    return (rc);
4025
0
  } else
4026
0
#endif
4027
0
    return (0);
4028
0
}
4029
4030
/* ******************************* */
4031
4032
/* Exec the command and returns fals ein case of error, or true otherwise */
4033
0
bool Utils::execCmd(char *cmd, std::string *out) {
4034
0
#ifndef WIN32
4035
0
  FILE *fp;
4036
4037
  /* Do not start commands during shutdown */
4038
0
  if(ntop->getGlobals()->isShutdownRequested()) {
4039
0
    ntop->getTrace()->traceEvent(TRACE_WARNING, "Skipping command during shutdown (%s)", cmd);
4040
0
    return(false);
4041
0
  }
4042
  
4043
0
  ntop->getTrace()->traceEvent(TRACE_INFO, "Executing %s", cmd);
4044
4045
0
  if ((fp = popen(cmd, "r")) != NULL) {
4046
0
    char line[256], *l;
4047
0
    int fd = fileno(fp);
4048
    
4049
0
    while(!ntop->getGlobals()->isShutdownRequested()) {
4050
0
      struct timeval ts;
4051
0
      fd_set rset;
4052
0
      int ret;
4053
      
4054
0
      FD_ZERO(&rset);
4055
0
      FD_SET(fd, &rset);
4056
0
      ts.tv_sec = 1, ts.tv_usec = 0;
4057
      
4058
0
      ret = select(fd + 1, &rset, NULL, NULL, &ts);
4059
4060
0
      if(ret < 0)
4061
0
  break;
4062
0
      else if(ret > 0) {
4063
0
  if((l = fgets(line, sizeof(line), fp)) != NULL) {
4064
0
    out->append(l);
4065
0
    continue;
4066
0
  } else
4067
0
    break;
4068
0
      }
4069
      
4070
0
      ntop->getTrace()->traceEvent(TRACE_INFO, "Sleeping %s", cmd);
4071
      
4072
0
      _usleep(100000);
4073
0
    } /* while */
4074
4075
0
    if(ntop->getGlobals()->isShutdownRequested())
4076
0
      ; /* Do not call pclose() otherwise we need to wait until the command ends */
4077
0
    else
4078
0
      pclose(fp);
4079
4080
0
    ntop->getTrace()->traceEvent(TRACE_INFO, "Executed (%s) completed", cmd);
4081
0
    return(true);
4082
0
  } else
4083
0
#endif
4084
0
    return(false);
4085
0
}
4086
4087
/* ******************************* */
4088
4089
void Utils::maximizeSocketBuffer(int sock_fd, bool rx_buffer,
4090
0
                                 u_int max_buf_mb) {
4091
0
  int i, rcv_buffsize_base, rcv_buffsize,
4092
0
      max_buf_size = 1024 * max_buf_mb * 1024, debug = 0;
4093
0
  socklen_t len = sizeof(rcv_buffsize_base);
4094
0
  int buf_type = rx_buffer ? SO_RCVBUF /* RX */ : SO_SNDBUF /* TX */;
4095
4096
0
  if (getsockopt(sock_fd, SOL_SOCKET, buf_type, (char *)&rcv_buffsize_base,
4097
0
                 &len) < 0) {
4098
0
    ntop->getTrace()->traceEvent(
4099
0
        TRACE_ERROR, "Unable to read socket receiver buffer size [%s]",
4100
0
        strerror(errno));
4101
0
    return;
4102
0
  } else {
4103
0
    if (debug)
4104
0
      ntop->getTrace()->traceEvent(
4105
0
          TRACE_INFO, "Default socket %s buffer size is %d",
4106
0
          buf_type == SO_RCVBUF ? "receive" : "send", rcv_buffsize_base);
4107
0
  }
4108
4109
0
  for (i = 2;; i++) {
4110
0
    rcv_buffsize = i * rcv_buffsize_base;
4111
0
    if (rcv_buffsize > max_buf_size) break;
4112
4113
0
    if (setsockopt(sock_fd, SOL_SOCKET, buf_type, (const char *)&rcv_buffsize,
4114
0
                   sizeof(rcv_buffsize)) < 0) {
4115
0
      if (debug)
4116
0
        ntop->getTrace()->traceEvent(
4117
0
            TRACE_ERROR, "Unable to set socket %s buffer size [%s]",
4118
0
            buf_type == SO_RCVBUF ? "receive" : "send", strerror(errno));
4119
0
      break;
4120
0
    } else if (debug)
4121
0
      ntop->getTrace()->traceEvent(TRACE_INFO, "%s socket buffer size set %d",
4122
0
                                   buf_type == SO_RCVBUF ? "Receive" : "Send",
4123
0
                                   rcv_buffsize);
4124
0
  }
4125
0
}
4126
4127
/* ****************************************************** */
4128
4129
0
char *Utils::formatTraffic(float numBits, bool bits, char *buf) {
4130
0
  char unit;
4131
4132
0
  if (bits)
4133
0
    unit = 'b';
4134
0
  else
4135
0
    unit = 'B';
4136
4137
0
  if (numBits < 1024) {
4138
0
    snprintf(buf, 32, "%lu %c", (unsigned long)numBits, unit);
4139
0
  } else if (numBits < 1048576) {
4140
0
    snprintf(buf, 32, "%.2f K%c", (float)(numBits) / 1024, unit);
4141
0
  } else {
4142
0
    float tmpMBits = ((float)numBits) / 1048576;
4143
4144
0
    if (tmpMBits < 1024) {
4145
0
      snprintf(buf, 32, "%.2f M%c", tmpMBits, unit);
4146
0
    } else {
4147
0
      tmpMBits /= 1024;
4148
4149
0
      if (tmpMBits < 1024) {
4150
0
        snprintf(buf, 32, "%.2f G%c", tmpMBits, unit);
4151
0
      } else {
4152
0
        snprintf(buf, 32, "%.2f T%c", (float)(tmpMBits) / 1024, unit);
4153
0
      }
4154
0
    }
4155
0
  }
4156
4157
0
  return (buf);
4158
0
}
4159
4160
/* ****************************************************** */
4161
4162
0
char *Utils::formatPackets(float numPkts, char *buf) {
4163
0
  if (numPkts < 1000) {
4164
0
    snprintf(buf, 32, "%.2f", numPkts);
4165
0
  } else if (numPkts < 1000000) {
4166
0
    snprintf(buf, 32, "%.2f K", numPkts / 1000);
4167
0
  } else {
4168
0
    numPkts /= 1000000;
4169
0
    snprintf(buf, 32, "%.2f M", numPkts);
4170
0
  }
4171
4172
0
  return (buf);
4173
0
}
4174
4175
/* ****************************************************** */
4176
4177
0
bool Utils::str2DetailsLevel(const char *details, DetailsLevel *out) {
4178
0
  bool rv = false;
4179
4180
0
  if (!strcmp(details, "normal")) {
4181
0
    *out = details_normal;
4182
0
    rv = true;
4183
0
  } else if (!strcmp(details, "high")) {
4184
0
    *out = details_high;
4185
0
    rv = true;
4186
0
  } else if (!strcmp(details, "higher")) {
4187
0
    *out = details_higher;
4188
0
    rv = true;
4189
0
  } else if (!strcmp(details, "max")) {
4190
0
    *out = details_max;
4191
0
    rv = true;
4192
0
  }
4193
4194
0
  return rv;
4195
0
}
4196
4197
/* ****************************************************** */
4198
4199
0
bool Utils::isCriticalNetworkProtocol(u_int16_t protocol_id) {
4200
0
  return (protocol_id == NDPI_PROTOCOL_DNS) ||
4201
0
         (protocol_id == NDPI_PROTOCOL_DHCP);
4202
0
}
4203
4204
/* ****************************************************** */
4205
4206
u_int32_t Utils::roundTime(u_int32_t now, u_int32_t rounder,
4207
0
                           int32_t offset_from_utc) {
4208
  /* Align result to rounder. Operations intrinsically work in UTC. */
4209
0
  u_int32_t result = now - (now % rounder);
4210
0
  result += rounder;
4211
4212
  /* Aling now to localtime using the local offset from UTC.
4213
     So for example UTC+1, which has a +3600 offset from UTC, will have the
4214
     local time one hour behind, that is, 10PM UTC are 9PM UTC+1. For an UTC-1,
4215
     which has a -3600 offset from UTC, the local time is one hour ahead, that
4216
     is, 10PM UTC are 11PM UTC-1. Hence, in practice, a negative offset needs to
4217
     be added whereas a positive offset needs to be substracted. */
4218
0
  result += -offset_from_utc;
4219
4220
  /* Don't allow results which are earlier than now. Adjust using rounder until
4221
     now is reached. This can happen when result has been adjusted with a
4222
     positive offset from UTC. */
4223
0
  while (result <= now) result += rounder;
4224
4225
0
  return result;
4226
0
}
4227
4228
/* ************************************************* */
4229
4230
/*
4231
  now
4232
  now+1h   (hour)
4233
  now+1d   (day)
4234
  now+1w   (week)
4235
  now+1m   (month)
4236
  now+1min (minute)
4237
  now+1y   (year)
4238
*/
4239
0
u_int32_t Utils::parsetime(char *str) {
4240
0
  if (!strncmp(str, "now", 3)) {
4241
0
    char op = str[3];
4242
0
    int v;
4243
0
    char what[64];
4244
0
    u_int32_t ret = time(NULL);
4245
4246
0
    if (op == '\0')
4247
0
      return (ret);
4248
0
    else if (sscanf(&str[4], "%d%s", &v, what) == 2) {
4249
0
      if (!strcmp(what, "h"))
4250
0
        v *= 3600;
4251
0
      else if (!strcmp(what, "d"))
4252
0
        v *= 3600 * 24;
4253
0
      else if (!strcmp(what, "w"))
4254
0
        v *= 3600 * 24 * 7;
4255
0
      else if (!strcmp(what, "m"))
4256
0
        v *= 3600 * 24 * 7 * 30;
4257
0
      else if (!strcmp(what, "min"))
4258
0
        v *= 60;
4259
0
      else if (!strcmp(what, "y"))
4260
0
        v *= 3600 * 24 * 7 * 365;
4261
4262
0
      if (op == '-')
4263
0
        ret -= v;
4264
0
      else
4265
0
        ret += v;
4266
4267
0
      return (ret);
4268
0
    } else
4269
0
      return (0);
4270
0
  } else
4271
0
    return (atol(str));
4272
0
}
4273
4274
/* ************************************************* */
4275
4276
0
u_int64_t Utils::mac2int(const u_int8_t *mac) {
4277
0
  u_int64_t m = 0;
4278
4279
0
  memcpy(&m, mac, 6);
4280
0
  return (m);
4281
0
}
4282
4283
/* ************************************************* */
4284
4285
0
u_int8_t *Utils::int2mac(u_int64_t mac, u_int8_t *buf) {
4286
0
  memcpy(buf, &mac, 6);
4287
0
  buf[6] = buf[7] = '\0';
4288
0
  return (buf);
4289
0
}
4290
4291
/* ************************************************* */
4292
4293
void Utils::init_pcap_header(struct pcap_file_header *const h, int linktype,
4294
0
                             int snaplen, bool nsec) {
4295
  /*
4296
   * [0000000] c3d4 a1b2 0002 0004 0000 0000 0000 0000
4297
   * [0000010] 05ea 0000 0001 0000
4298
   */
4299
0
  if (!h) return;
4300
4301
0
  memset(h, 0, sizeof(*h));
4302
4303
0
  h->magic = nsec ? PCAP_NSEC_MAGIC : PCAP_MAGIC;
4304
0
  h->version_major = 2;
4305
0
  h->version_minor = 4;
4306
0
  h->thiszone = 0;
4307
0
  h->sigfigs = 0;
4308
0
  h->snaplen = snaplen;
4309
0
  h->linktype = linktype;
4310
0
}
4311
4312
/* ****************************************************** */
4313
4314
0
void Utils::listInterfaces(lua_State *vm) {
4315
0
  ntop_if_t *devpointer, *cur;
4316
4317
0
  if (Utils::ntop_findalldevs(&devpointer) != 0) return; /* Error */
4318
4319
0
  for (cur = devpointer; cur; cur = cur->next) {
4320
0
    lua_newtable(vm);
4321
4322
0
    if (cur->name) {
4323
0
      struct sockaddr_in sin;
4324
0
      struct sockaddr_in6 sin6;
4325
0
      char buf[64];
4326
4327
0
      if (cur->module) lua_push_str_table_entry(vm, "module", cur->module);
4328
4329
0
      sin.sin_family = AF_INET;
4330
0
      sin.sin_addr.s_addr = Utils::readIPv4(cur->name);
4331
4332
0
      if (sin.sin_addr.s_addr != 0)
4333
0
        lua_push_str_table_entry(
4334
0
            vm, "ipv4",
4335
0
            Utils::intoaV4(ntohl(sin.sin_addr.s_addr), buf, sizeof(buf)));
4336
4337
0
#ifndef WIN32
4338
0
      sin6.sin6_family = AF_INET6;
4339
0
      if (Utils::readIPv6(cur->name, &sin6.sin6_addr)) {
4340
0
        struct ndpi_in6_addr *ip6 = (struct ndpi_in6_addr *)&sin6.sin6_addr;
4341
0
        char *ip = Utils::intoaV6(*ip6, 128, buf, sizeof(buf));
4342
4343
0
        lua_push_str_table_entry(vm, "ipv6", ip);
4344
0
      }
4345
0
#endif
4346
0
    }
4347
4348
0
    lua_pushstring(vm, cur->name);
4349
0
    lua_insert(vm, -2);
4350
0
    lua_settable(vm, -3);
4351
0
  }
4352
4353
0
  Utils::ntop_freealldevs(devpointer);
4354
0
}
4355
4356
/* ****************************************************** */
4357
4358
0
char *Utils::ntop_lookupdev(char *ifname_out, int ifname_size) {
4359
0
  char ebuf[PCAP_ERRBUF_SIZE];
4360
0
  pcap_if_t *pdevs, *pdev;
4361
0
  bool found = false;
4362
4363
0
  ifname_out[0] = '\0';
4364
4365
0
  if (pcap_findalldevs(&pdevs, ebuf) != 0) goto err;
4366
4367
0
  pdev = pdevs;
4368
0
  while (pdev != NULL) {
4369
0
    if (Utils::validInterface(pdev) && Utils::isInterfaceUp(pdev->name)) {
4370
0
      snprintf(ifname_out, ifname_size, "%s", pdev->name);
4371
0
      found = true;
4372
0
      break;
4373
0
    }
4374
0
    pdev = pdev->next;
4375
0
  }
4376
4377
0
  pcap_freealldevs(pdevs);
4378
4379
0
err:
4380
0
  return found ? ifname_out : NULL;
4381
0
}
4382
4383
/* ****************************************************** */
4384
4385
4
int Utils::ntop_findalldevs(ntop_if_t **alldevsp) {
4386
4
  char ebuf[PCAP_ERRBUF_SIZE];
4387
4
  pcap_if_t *pdevs, *pdev;
4388
#ifdef HAVE_PF_RING
4389
  pfring_if_t *pfdevs, *pfdev;
4390
#endif
4391
4
  ntop_if_t *tail = NULL;
4392
4
  ntop_if_t *cur;
4393
4394
4
  if (!alldevsp) return -1;
4395
4396
4
  *alldevsp = NULL;
4397
4398
4
  if (pcap_findalldevs(&pdevs, ebuf) != 0) return -1;
4399
4400
#ifdef HAVE_PF_RING
4401
  pfdevs = pfring_findalldevs();
4402
4403
  pfdev = pfdevs;
4404
  while (pfdev != NULL) {
4405
    /* merge with info from pcap */
4406
    pdev = pdevs;
4407
    while (pdev != NULL) {
4408
      if (pfdev->system_name && strcmp(pfdev->system_name, pdev->name) == 0)
4409
        break;
4410
      pdev = pdev->next;
4411
    }
4412
4413
    if (pdev == NULL /* not a standard interface (e.g. fpga) */
4414
        || (Utils::isInterfaceUp(pfdev->system_name) &&
4415
            Utils::validInterface(pdev))) {
4416
      cur = (ntop_if_t *)calloc(1, sizeof(ntop_if_t));
4417
4418
      if (cur) {
4419
        cur->name =
4420
            strdup(pfdev->system_name ? pfdev->system_name : pfdev->name);
4421
        cur->description =
4422
            strdup((pdev && pdev->description) ? pdev->description : "");
4423
        cur->module = strdup(pfdev->module);
4424
        cur->license = pfdev->license;
4425
4426
        if (!*alldevsp) *alldevsp = cur;
4427
        if (tail) tail->next = cur;
4428
        tail = cur;
4429
      }
4430
    }
4431
4432
    pfdev = pfdev->next;
4433
  }
4434
#endif
4435
4436
4
  pdev = pdevs;
4437
24
  while (pdev != NULL) {
4438
20
    if (Utils::validInterface(pdev) && Utils::isInterfaceUp(pdev->name)) {
4439
#ifdef HAVE_PF_RING
4440
      /* check if already listed */
4441
      pfdev = pfdevs;
4442
      while (pfdev != NULL) {
4443
        if (strcmp(pfdev->system_name, pdev->name) == 0) break;
4444
        pfdev = pfdev->next;
4445
      }
4446
4447
      if (pfdev == NULL) {
4448
#endif
4449
8
        cur = (ntop_if_t *)calloc(1, sizeof(ntop_if_t));
4450
4451
8
        if (cur) {
4452
8
          cur->name = strdup(pdev->name);
4453
8
          cur->description = strdup(pdev->description ? pdev->description : "");
4454
4455
8
          if (!*alldevsp) *alldevsp = cur;
4456
8
          if (tail) tail->next = cur;
4457
8
          tail = cur;
4458
8
        }
4459
#ifdef HAVE_PF_RING
4460
      }
4461
#endif
4462
8
    }
4463
4464
20
    pdev = pdev->next;
4465
20
  }
4466
4467
#ifdef HAVE_PF_RING
4468
  pfring_freealldevs(pfdevs);
4469
#endif
4470
4
  pcap_freealldevs(pdevs);
4471
4472
4
  return 0;
4473
4
}
4474
4475
/* ****************************************************** */
4476
4477
4
void Utils::ntop_freealldevs(ntop_if_t *alldevsp) {
4478
4
  ntop_if_t *cur;
4479
4480
12
  while (alldevsp) {
4481
8
    cur = alldevsp;
4482
8
    alldevsp = alldevsp->next;
4483
4484
8
    if (cur->name) free(cur->name);
4485
8
    if (cur->description) free(cur->description);
4486
8
    if (cur->module) free(cur->module);
4487
4488
8
    free(cur);
4489
8
  }
4490
4
}
4491
4492
/* ****************************************************** */
4493
4494
20
bool Utils::validInterfaceName(const char *name) {
4495
20
#if not defined(WIN32)
4496
20
  if (!name || !strncmp(name, "virbr", 5) /* Ignore virtual interfaces */
4497
20
  )
4498
0
    return false;
4499
4500
  /*
4501
     Make strict checks when validating interface names. This is fundamental
4502
     To prevent injections in syscalls such as system() or popen(). Indeed,
4503
     interface names can be fancy and contain special characters, e.g,.
4504
4505
     $ ip link add link eno1 name "\";whoami>b;\"" type vlan id 8
4506
     $ nmcli con add type vlan ifname ";whoami>b;" dev enp1s0 id 10
4507
4508
     Hence, a valid interface name must have strict requirements.
4509
  */
4510
104
  for (int i = 0; name[i] != '\0'; i++) {
4511
84
    if (!isalnum(name[i]) && name[i] != '@' && name[i] != '-' &&
4512
84
        name[i] != ':' && name[i] != '_')
4513
0
      return false;
4514
84
  }
4515
20
#endif
4516
4517
20
  return true;
4518
20
}
4519
4520
/* ****************************************************** */
4521
4522
20
bool Utils::validInterfaceDescription(const char *description) {
4523
20
  if (description &&
4524
20
      (strstr(description, "PPP") /* Skip the PPP interface              */
4525
12
       || strstr(description, "dialup")   /* Skip the dialup interface   */
4526
12
       || strstr(description, "Miniport") /* Skip the miniport interface */
4527
12
       ||
4528
12
       strstr(description, "ICSHARE") /* Skip the internet sharing interface */
4529
12
       || strstr(description,
4530
12
                 "NdisWan"))) { /* Skip the internet sharing interface */
4531
0
    return false;
4532
0
  }
4533
4534
20
  return true;
4535
20
}
4536
4537
/* ****************************************************** */
4538
4539
0
bool Utils::validInterface(const ntop_if_t *ntop_if) {
4540
0
  return Utils::validInterfaceName(ntop_if->name) &&
4541
0
         Utils::validInterfaceDescription(ntop_if->description);
4542
0
}
4543
4544
/* ****************************************************** */
4545
4546
20
bool Utils::validInterface(const pcap_if_t *pcap_if) {
4547
20
  return Utils::validInterfaceName(pcap_if->name) &&
4548
20
         Utils::validInterfaceDescription(pcap_if->description);
4549
20
}
4550
4551
/* ****************************************************** */
4552
4553
0
const char *Utils::policySource2Str(L7PolicySource_t policy_source) {
4554
0
  switch (policy_source) {
4555
0
    case policy_source_pool:
4556
0
      return "policy_source_pool";
4557
0
    case policy_source_protocol:
4558
0
      return "policy_source_protocol";
4559
0
    case policy_source_category:
4560
0
      return "policy_source_category";
4561
0
    case policy_source_device_protocol:
4562
0
      return "policy_source_device_protocol";
4563
0
    case policy_source_schedule:
4564
0
      return "policy_source_schedule";
4565
0
    default:
4566
0
      return "policy_source_default";
4567
0
  }
4568
0
}
4569
4570
/* ****************************************************** */
4571
4572
0
const char *Utils::captureDirection2Str(pcap_direction_t dir) {
4573
0
  switch (dir) {
4574
0
    case PCAP_D_IN:
4575
0
      return "in";
4576
0
    case PCAP_D_OUT:
4577
0
      return "out";
4578
0
    case PCAP_D_INOUT:
4579
0
    default:
4580
0
      return "inout";
4581
0
  }
4582
0
}
4583
4584
/* ****************************************************** */
4585
4586
bool Utils::readInterfaceStats(const char *ifname, ProtoStats *in_stats,
4587
0
                               ProtoStats *out_stats) {
4588
0
  bool rv = false;
4589
0
#ifndef WIN32
4590
0
  FILE *f = fopen("/proc/net/dev", "r");
4591
4592
0
  if (f) {
4593
0
    char line[512];
4594
0
    char to_find[IFNAMSIZ + 2];
4595
0
    snprintf(to_find, sizeof(to_find), "%s:", ifname);
4596
4597
0
    while (fgets(line, sizeof(line), f)) {
4598
0
      long long unsigned int in_bytes, out_bytes, in_packets, out_packets;
4599
4600
0
      if (strstr(line, to_find) &&
4601
0
          sscanf(line, "%*[^:]: %llu %llu %*u %*u %*u %*u %*u %*u %llu %llu",
4602
0
                 &in_bytes, &in_packets, &out_bytes, &out_packets) == 4) {
4603
0
        ntop->getTrace()->traceEvent(
4604
0
            TRACE_DEBUG,
4605
0
            "iface_counters: in_bytes=%llu in_packets=%llu - out_bytes=%llu "
4606
0
            "out_packets=%llu",
4607
0
            in_bytes, in_packets, out_bytes, out_packets);
4608
0
        in_stats->setBytes(in_bytes);
4609
0
        in_stats->setPkts(in_packets);
4610
0
        out_stats->setBytes(out_bytes);
4611
0
        out_stats->setPkts(out_packets);
4612
0
        rv = true;
4613
0
        break;
4614
0
      }
4615
0
    }
4616
0
  }
4617
4618
0
  if (f) fclose(f);
4619
0
#endif
4620
4621
0
  return rv;
4622
0
}
4623
4624
/* ****************************************************** */
4625
4626
14.5k
bool Utils::shouldResolveHost(const char *host_ip) {
4627
14.5k
  if (!ntop->getPrefs()->is_dns_resolution_enabled()) return false;
4628
4629
14.5k
  if (!ntop->getPrefs()->is_dns_resolution_enabled_for_all_hosts()) {
4630
    /*
4631
      In case only local addresses need to be resolved, skip
4632
      remote hosts
4633
    */
4634
14.5k
    IpAddress ip;
4635
4636
14.5k
    ip.set((char *)host_ip);
4637
14.5k
    if (!ip.isLocalHost()) return false;
4638
14.5k
  }
4639
4640
14.5k
  return true;
4641
14.5k
}
4642
4643
/* ****************************************************** */
4644
4645
0
bool Utils::mg_write_retry(struct mg_connection *conn, u_char *b, int len) {
4646
0
  int ret, sent = 0;
4647
0
  time_t max_retry = 1000;
4648
4649
0
  while (!ntop->getGlobals()->isShutdown() && --max_retry) {
4650
0
    ret = mg_write_async(conn, &b[sent], len - sent);
4651
0
    if (ret < 0) return false;
4652
0
    sent += ret;
4653
0
    if (sent == len) return true;
4654
0
    _usleep(100);
4655
0
  }
4656
4657
0
  return false;
4658
0
}
4659
4660
/* ****************************************************** */
4661
4662
0
bool Utils::parseAuthenticatorJson(HTTPAuthenticator *auth, char *content) {
4663
0
  json_object *o;
4664
0
  enum json_tokener_error jerr = json_tokener_success;
4665
4666
0
  o = json_tokener_parse_verbose(content, &jerr);
4667
0
  if (o) {
4668
0
    json_object *w;
4669
4670
0
    if (json_object_object_get_ex(o, "admin", &w))
4671
0
      auth->admin = (bool)json_object_get_boolean(w);
4672
4673
0
    if (json_object_object_get_ex(o, "allowedIfname", &w))
4674
0
      auth->allowedIfname = strdup((char *)json_object_get_string(w));
4675
4676
0
    if (json_object_object_get_ex(o, "allowedNets", &w))
4677
0
      auth->allowedNets = strdup((char *)json_object_get_string(w));
4678
4679
0
    if (json_object_object_get_ex(o, "language", &w))
4680
0
      auth->language = strdup((char *)json_object_get_string(w));
4681
4682
0
    json_object_put(o);
4683
0
    return true;
4684
0
  }
4685
0
  return false;
4686
0
}
4687
4688
/* ****************************************************** */
4689
4690
0
void Utils::freeAuthenticator(HTTPAuthenticator *auth) {
4691
0
  if (auth == NULL) return;
4692
0
  if (auth->allowedIfname) free(auth->allowedIfname);
4693
0
  if (auth->allowedNets) free(auth->allowedNets);
4694
0
  if (auth->language) free(auth->language);
4695
0
}
4696
4697
/* ****************************************************** */
4698
4699
0
DetailsLevel Utils::bool2DetailsLevel(bool max, bool higher, bool normal) {
4700
0
  if (max) {
4701
0
    return details_max;
4702
0
  } else if (higher) {
4703
0
    return details_higher;
4704
0
  } else if (normal) {
4705
0
    return details_normal;
4706
0
  } else {
4707
0
    return details_high;
4708
0
  }
4709
0
}
4710
4711
/* ****************************************************** */
4712
4713
0
void Utils::containerInfoLua(lua_State *vm, const ContainerInfo *const cont) {
4714
0
  lua_newtable(vm);
4715
4716
0
  if (cont->id) lua_push_str_table_entry(vm, "id", cont->id);
4717
0
  if (cont->data_type == container_info_data_type_k8s) {
4718
0
    if (cont->name) lua_push_str_table_entry(vm, "k8s.name", cont->name);
4719
0
    if (cont->data.k8s.pod)
4720
0
      lua_push_str_table_entry(vm, "k8s.pod", cont->data.k8s.pod);
4721
0
    if (cont->data.k8s.ns)
4722
0
      lua_push_str_table_entry(vm, "k8s.ns", cont->data.k8s.ns);
4723
0
  } else if (cont->data_type == container_info_data_type_docker) {
4724
0
    if (cont->name) lua_push_str_table_entry(vm, "docker.name", cont->name);
4725
0
  }
4726
0
}
4727
4728
/* ****************************************************** */
4729
4730
0
const char *Utils::periodicityToScriptName(ScriptPeriodicity p) {
4731
0
  switch (p) {
4732
0
    case aperiodic_script:
4733
0
      return ("aperiodic");
4734
0
    case minute_script:
4735
0
      return ("min");
4736
0
    case five_minute_script:
4737
0
      return ("5mins");
4738
0
    case hour_script:
4739
0
      return ("hour");
4740
0
    case day_script:
4741
0
      return ("day");
4742
0
    default:
4743
0
      ntop->getTrace()->traceEvent(TRACE_WARNING,
4744
0
                                   "Unknown periodicity value: %d", p);
4745
0
      return ("");
4746
0
  }
4747
0
}
4748
4749
/* ****************************************************** */
4750
4751
0
int Utils::periodicityToSeconds(ScriptPeriodicity p) {
4752
0
  switch (p) {
4753
0
    case aperiodic_script:
4754
0
      return (0);
4755
0
    case minute_script:
4756
0
      return (60);
4757
0
    case five_minute_script:
4758
0
      return (300);
4759
0
    case hour_script:
4760
0
      return (3600);
4761
0
    case day_script:
4762
0
      return (86400);
4763
0
    default:
4764
0
      ntop->getTrace()->traceEvent(TRACE_WARNING,
4765
0
                                   "Unknown periodicity value: %d", p);
4766
0
      return (0);
4767
0
  }
4768
0
}
4769
4770
/* ****************************************************** */
4771
4772
/* TODO move into nDPI */
4773
OSType Utils::getOSFromFingerprint(const char *fingerprint, const char *manuf,
4774
0
                                   DeviceType devtype) {
4775
  /*
4776
    Inefficient with many signatures but ok for the
4777
    time being that we have little data
4778
  */
4779
0
  if (!fingerprint) return (os_unknown);
4780
4781
0
  if (!strcmp(fingerprint, "017903060F77FC"))
4782
0
    return (os_ios);
4783
0
  else if ((!strcmp(fingerprint, "017903060F77FC5F2C2E")) ||
4784
0
           (!strcmp(fingerprint, "0103060F775FFC2C2E2F")) ||
4785
0
           (!strcmp(fingerprint, "0103060F775FFC2C2E")))
4786
0
    return (os_macos);
4787
0
  else if ((!strcmp(fingerprint, "0103060F1F212B2C2E2F79F9FC")) ||
4788
0
           (!strcmp(fingerprint, "010F03062C2E2F1F2179F92B")))
4789
0
    return (os_windows);
4790
0
  else if ((!strcmp(fingerprint, "0103060C0F1C2A")) ||
4791
0
           (!strcmp(fingerprint, "011C02030F06770C2C2F1A792A79F921FC2A")))
4792
0
    return (os_linux); /* Android is also linux */
4793
0
  else if ((!strcmp(fingerprint, "0603010F0C2C51452B1242439607")) ||
4794
0
           (!strcmp(fingerprint, "01032C06070C0F16363A3B45122B7751999A")))
4795
0
    return (os_laserjet);
4796
0
  else if (!strcmp(fingerprint, "0102030F060C2C"))
4797
0
    return (os_apple_airport);
4798
0
  else if (!strcmp(fingerprint, "01792103060F1C333A3B77"))
4799
0
    return (os_android);
4800
4801
  /* Below you can find ambiguous signatures */
4802
0
  if (manuf) {
4803
0
    if (!strcmp(fingerprint, "0103063633")) {
4804
0
      if (strstr(manuf, "Apple"))
4805
0
        return (os_macos);
4806
0
      else if (devtype == device_unknown)
4807
0
        return (os_windows);
4808
0
    }
4809
0
  }
4810
4811
0
  return (os_unknown);
4812
0
}
4813
/*
4814
  Missing OS mapping
4815
4816
  011C02030F06770C2C2F1A792A
4817
  010F03062C2E2F1F2179F92BFC
4818
*/
4819
4820
/* ****************************************************** */
4821
4822
/* TODO move into nDPI? */
4823
68
DeviceType Utils::getDeviceTypeFromOsDetail(const char *os) {
4824
68
  if (strcasestr(os, "iPhone") || strcasestr(os, "Android") ||
4825
68
      strcasestr(os, "mobile"))
4826
25
    return (device_phone);
4827
43
  else if (strcasestr(os, "Mac OS") || strcasestr(os, "Windows") ||
4828
43
           strcasestr(os, "Linux"))
4829
24
    return (device_workstation);
4830
19
  else if (strcasestr(os, "iPad") || strcasestr(os, "tablet"))
4831
5
    return (device_tablet);
4832
4833
14
  return (device_unknown);
4834
68
}
4835
4836
/* Bitmap functions */
4837
0
bool Utils::bitmapIsSet(u_int64_t bitmap, u_int8_t v) {
4838
0
  if (v > 64) {
4839
0
    ntop->getTrace()->traceEvent(
4840
0
        TRACE_WARNING, "INTERNAL ERROR: bitmapIsSet out of range (%u > %u)", v,
4841
0
        sizeof(bitmap));
4842
0
    return (false);
4843
0
  }
4844
4845
0
  return (((bitmap >> v) & 1) ? true : false);
4846
0
}
4847
4848
0
u_int64_t Utils::bitmapSet(u_int64_t bitmap, u_int8_t v) {
4849
0
  if (v > 64)
4850
0
    ntop->getTrace()->traceEvent(
4851
0
        TRACE_WARNING, "INTERNAL ERROR: bitmapSet out of range (%u > %u)", v,
4852
0
        sizeof(bitmap));
4853
0
  else
4854
0
    bitmap |= ((u_int64_t)1) << v;
4855
4856
0
  return (bitmap);
4857
0
}
4858
4859
0
u_int64_t Utils::bitmapClear(u_int64_t bitmap, u_int8_t v) {
4860
0
  if (v > 64)
4861
0
    ntop->getTrace()->traceEvent(
4862
0
        TRACE_WARNING, "INTERNAL ERROR: bitmapClear out of range (%u > %u)", v,
4863
0
        sizeof(bitmap));
4864
0
  else
4865
0
    bitmap &= ~(((u_int64_t)1) << v);
4866
4867
0
  return (bitmap);
4868
0
}
4869
4870
/* ****************************************************** */
4871
4872
0
json_object *Utils::cloneJSONSimple(json_object *src) {
4873
0
  struct json_object_iterator obj_it = json_object_iter_begin(src);
4874
0
  struct json_object_iterator obj_itEnd = json_object_iter_end(src);
4875
0
  json_object *obj = json_object_new_object();
4876
4877