Coverage Report

Created: 2025-11-16 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ntopng/fuzz/fuzz_dissect_packet.cpp
Line
Count
Source
1
/*
2
 *
3
 * (C) 2013-23 - ntop.org
4
 *
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software Foundation,
18
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
 *
20
 */
21
22
#ifdef FUZZ_WITH_PROTOBUF
23
#include <bits/types/struct_timeval.h>
24
#include <src/libfuzzer/libfuzzer_macro.h>
25
#include <sys/time.h>
26
27
#include "proto/pcap.pb.h"
28
#endif
29
30
#include <unistd.h>
31
32
#include "ntop_includes.h"
33
34
#ifdef INCLUDE_ONEFILE
35
#include "onefile.cpp"
36
#endif
37
38
AfterShutdownAction afterShutdownAction = after_shutdown_nop;
39
NetworkInterface *iface;
40
41
constexpr const char *PROG_NAME = "ntopng";
42
static ndpi_protocol ndpiUnknownProtocol;
43
44
bool trace_new_delete = false;
45
46
2
static void cleanup() {
47
2
  if (iface) delete iface;
48
2
  if (ntop) delete ntop;
49
2
}
50
51
/**
52
 * Set the CLI args for prefs.
53
 *
54
 * The function must be called like this:
55
 * setCLIArgs(Prefs *prefs, int params, const char * ...)
56
 */
57
2
static void setCLIArgs(Prefs *prefs, int params...) {
58
2
  if (params == 0) return;
59
60
2
  va_list args;
61
2
  va_start(args, params);
62
63
  // Get path of the binary itself. This is needed to get the absolute path of
64
  // the required directories
65
2
  char exePath[MAX_PATH + 1];
66
2
  ssize_t pathLen = readlink("/proc/self/exe", exePath, MAX_PATH);
67
2
  if (pathLen != -1) {
68
2
    exePath[pathLen] = '\0';
69
2
    ssize_t len = pathLen;
70
42
    while (len > 0 && exePath[len] != '/') len--;
71
2
    if (len == 0) {
72
0
      std::cerr << "Error while crafting the command line. Relative path "
73
0
  "have been used."
74
0
    << std::endl;
75
0
      exit(1);
76
0
    }
77
2
    exePath[len] = '\0';
78
2
    pathLen = len;
79
2
  } else {
80
0
    std::cerr << "Error while crafting the command line. Failed to "
81
0
      "retrieve the absolute path of the executable."
82
0
        << std::endl;
83
0
    exit(1);
84
0
  }
85
86
  // Create the new argv
87
2
  char *new_argv[params];
88
24
  for (int i = 0; i < params; ++i) {
89
22
    const char *opt = va_arg(args, const char *);
90
91
22
    if (!strstr(opt, "_PATH_")) {
92
12
      new_argv[i] = strdup(opt);
93
12
    } else {
94
      // size = pathLen + / + opt - _PATH_ + \0
95
10
      size_t size = pathLen + 1 + strlen(opt) - 6 + 1;
96
10
      new_argv[i] = (char *)malloc(size);
97
10
      int len = snprintf(new_argv[i], size, "%s/%s", exePath, opt + 6);
98
10
      if (len <= 0) {
99
0
  std::cerr << "Error while crafting the command line. Wrong "
100
0
    "buffer size."
101
0
      << std::endl;
102
0
  exit(1);
103
0
      }
104
10
    }
105
22
  }
106
107
2
  prefs->loadFromCLI(params, new_argv);  // = true;
108
109
  // Free arguments
110
24
  for (int k = 0; k < params; ++k) free(new_argv[k]);
111
112
2
  va_end(args);
113
2
}
114
115
183k
const ndpi_protocol getConstNdpiUnknownProtocol() {
116
183k
  return((const ndpi_protocol)ndpiUnknownProtocol);
117
183k
}
118
2
extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
119
  // Final cleanup
120
2
  atexit(cleanup);
121
122
2
  Prefs *prefs = NULL;
123
124
2
  if ((ntop = new (std::nothrow) Ntop(PROG_NAME)) == NULL) _exit(1);
125
2
  if ((prefs = new (std::nothrow) Prefs(ntop)) == NULL) _exit(1);
126
127
2
  ntop->getTrace()->set_trace_level(1);
128
2
  memset((void*)&ndpiUnknownProtocol, 0, sizeof(ndpiUnknownProtocol));
129
  
130
2
  setCLIArgs(prefs, 11, PROG_NAME, "-1", "_PATH_docs", "-2", "_PATH_scripts",
131
2
       "-3", "_PATH_scripts/callbacks", "-d", "_PATH_data-dir", "-t",
132
2
       "_PATH_install");
133
134
2
  ntop->registerPrefs(prefs, false);
135
136
2
  ntop->loadGeolocation();
137
138
2
  iface = new NetworkInterface("custom");
139
2
  iface->allocateStructures();
140
141
2
  return 0;
142
2
}
143
144
#ifdef FUZZ_WITH_PROTOBUF
145
146
template <class Proto>
147
using PostProcessor =
148
  protobuf_mutator::libfuzzer::PostProcessorRegistration<Proto>;
149
150
DEFINE_PROTO_FUZZER(const ntopng_fuzz::Pcap &message) {
151
  ntop->getTrace()->traceEvent(TRACE_INFO, "Starting");
152
153
  for (const ntopng_fuzz::Record &packet : message.packets()) {
154
    char pcap_error_buffer[PCAP_ERRBUF_SIZE];
155
    u_int16_t p;
156
    Host *srcHost = NULL, *dstHost = NULL;
157
    Flow *flow = NULL;
158
159
    const u_char *pkt =
160
      reinterpret_cast<const u_char *>(packet.data().data());
161
    struct pcap_pkthdr *hdr = new pcap_pkthdr();
162
163
    hdr->caplen = message.packets().size();
164
    hdr->len = packet.header().len();
165
    hdr->ts = {packet.header().timestamp(),
166
         packet.header().micronano_timestamp()};
167
168
    // printf("caplen %d len %d ts %d sus %d\n", hdr->caplen, hdr->len,
169
    //        hdr->ts.tv_sec, hdr->ts.tv_usec);
170
171
    iface->dissectPacket(UNKNOWN_PKT_IFACE_IDX,
172
       DUMMY_BRIDGE_INTERFACE_ID, true, DLT_NULL, NULL, hdr, pkt,
173
       &p, &srcHost, &dstHost, &flow);
174
    // ntop->getTrace()->traceEvent(TRACE_ERROR, "dissecting packet");
175
  }
176
  ntop->getTrace()->traceEvent(TRACE_INFO, "Ending");
177
}
178
179
#else
180
181
15.4k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
182
15.4k
  if (len == 0) return -1;
183
184
15.4k
  FILE *fd = fmemopen((void *)buf, len, "r");
185
15.4k
  if (fd == NULL) {
186
0
    std::cerr << "Cannot create the file descriptor with fmemopen"
187
0
        << std::endl;
188
0
    return -1;
189
0
  }
190
191
15.4k
  char pcap_error_buffer[PCAP_ERRBUF_SIZE];
192
15.4k
  pcap_t *pcap_handle;
193
15.4k
  const u_char *pkt;
194
15.4k
  struct pcap_pkthdr *hdr;
195
15.4k
  u_int16_t p;
196
15.4k
  Host *srcHost = NULL, *dstHost = NULL;
197
15.4k
  Flow *flow = NULL;
198
199
15.4k
  pcap_handle = pcap_fopen_offline(fd, pcap_error_buffer);
200
15.4k
  if (pcap_handle == NULL) goto end;
201
15.4k
  iface->set_datalink(pcap_datalink(pcap_handle));
202
15.4k
  pcap_setnonblock(pcap_handle, 1, pcap_error_buffer);
203
204
130k
  while (pcap_next_ex(pcap_handle, &hdr, &pkt) > 0) {
205
114k
    iface->dissectPacket(UNKNOWN_PKT_IFACE_IDX,
206
114k
       DUMMY_BRIDGE_INTERFACE_ID, DLT_NULL, true, NULL, hdr, pkt,
207
114k
       &p, &srcHost, &dstHost, &flow);
208
114k
  }
209
15.4k
  pcap_close(pcap_handle);
210
211
15.4k
 end:
212
15.4k
  iface->cleanup();
213
214
15.4k
  return 0;
215
15.4k
}
216
217
#endif