1 /* sharkd_session.c
2 *
3 * Copyright (C) 2016 Jakub Zawadzki
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "wtap_opttypes.h"
13 #include <config.h>
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <errno.h>
20
21 #include <glib.h>
22
23 #include <wsutil/wsjson.h>
24 #include <wsutil/json_dumper.h>
25 #include <wsutil/ws_assert.h>
26
27 #include <file.h>
28 #include <epan/epan_dissect.h>
29 #include <epan/exceptions.h>
30 #include <epan/color_filters.h>
31 #include <epan/prefs.h>
32 #include <epan/prefs-int.h>
33 #include <epan/uat-int.h>
34 #include <wiretap/wtap.h>
35
36 #include <epan/column.h>
37
38 #include <ui/ssl_key_export.h>
39
40 #include <ui/io_graph_item.h>
41 #include <epan/stats_tree_priv.h>
42 #include <epan/stat_tap_ui.h>
43 #include <epan/conversation_table.h>
44 #include <epan/sequence_analysis.h>
45 #include <epan/expert.h>
46 #include <epan/export_object.h>
47 #include <epan/follow.h>
48 #include <epan/rtd_table.h>
49 #include <epan/srt_table.h>
50
51 #include <epan/dissectors/packet-h225.h>
52 #include <epan/rtp_pt.h>
53 #include <ui/voip_calls.h>
54 #include <ui/rtp_stream.h>
55 #include <ui/tap-rtp-common.h>
56 #include <ui/tap-rtp-analysis.h>
57 #include <ui/version_info.h>
58 #include <epan/to_str.h>
59
60 #include <epan/addr_resolv.h>
61 #include <epan/dissectors/packet-rtp.h>
62 #include <ui/rtp_media.h>
63 #ifdef HAVE_SPEEXDSP
64 # include <speex/speex_resampler.h>
65 #else
66 # include "speexdsp/speex_resampler.h"
67 #endif /* HAVE_SPEEXDSP */
68
69 #include <epan/maxmind_db.h>
70
71 #include <wsutil/pint.h>
72 #include <wsutil/strtoi.h>
73
74 #include "globals.h"
75
76 #include "sharkd.h"
77
78 struct sharkd_filter_item
79 {
80 guint8 *filtered; /* can be NULL if all frames are matching for given filter. */
81 };
82
83 static GHashTable *filter_table = NULL;
84
85 static int mode;
86 static guint32 rpcid;
87
88 static json_dumper dumper = {0};
89
90
91 static const char *
json_find_attr(const char * buf,const jsmntok_t * tokens,int count,const char * attr)92 json_find_attr(const char *buf, const jsmntok_t *tokens, int count, const char *attr)
93 {
94 int i;
95
96 for (i = 0; i < count; i += 2)
97 {
98 const char *tok_attr = &buf[tokens[i + 0].start];
99 const char *tok_value = &buf[tokens[i + 1].start];
100
101 if (!strcmp(tok_attr, attr))
102 return tok_value;
103 }
104
105 return NULL;
106 }
107
108 static void
json_print_base64(const guint8 * data,size_t len)109 json_print_base64(const guint8 *data, size_t len)
110 {
111 json_dumper_begin_base64(&dumper);
112 json_dumper_write_base64(&dumper, data, len);
113 json_dumper_end_base64(&dumper);
114 }
115
116 static void G_GNUC_PRINTF(2, 3)
sharkd_json_value_anyf(const char * key,const char * format,...)117 sharkd_json_value_anyf(const char *key, const char *format, ...)
118 {
119 if (key)
120 json_dumper_set_member_name(&dumper, key);
121
122 if (format) {
123 va_list ap;
124 va_start(ap, format);
125 json_dumper_value_va_list(&dumper, format, ap);
126 va_end(ap);
127 }
128 }
129
130 static void
sharkd_json_value_string(const char * key,const char * str)131 sharkd_json_value_string(const char *key, const char *str)
132 {
133 if (key)
134 json_dumper_set_member_name(&dumper, key);
135 if (str)
136 json_dumper_value_string(&dumper, str);
137 }
138
139 static void
sharkd_json_value_base64(const char * key,const guint8 * data,size_t len)140 sharkd_json_value_base64(const char *key, const guint8 *data, size_t len)
141 {
142 if (key)
143 json_dumper_set_member_name(&dumper, key);
144 json_print_base64(data, len);
145 }
146
147 static void G_GNUC_PRINTF(2, 3)
sharkd_json_value_stringf(const char * key,const char * format,...)148 sharkd_json_value_stringf(const char *key, const char *format, ...)
149 {
150 if (key)
151 json_dumper_set_member_name(&dumper, key);
152
153 if (format) {
154 va_list ap;
155 va_start(ap, format);
156 char* sformat = g_strdup_printf("\"%s\"", format);
157 json_dumper_value_va_list(&dumper, sformat, ap);
158 g_free(sformat);
159 va_end(ap);
160 }
161 }
162
163 static void
sharkd_json_array_open(const char * key)164 sharkd_json_array_open(const char *key)
165 {
166 if (key)
167 json_dumper_set_member_name(&dumper, key);
168 json_dumper_begin_array(&dumper);
169 }
170
171 static void
sharkd_json_array_close(void)172 sharkd_json_array_close(void)
173 {
174 json_dumper_end_array(&dumper);
175 }
176
177 static void
sharkd_json_response_open(guint32 id)178 sharkd_json_response_open(guint32 id)
179 {
180 json_dumper_begin_object(&dumper); // start the message
181 sharkd_json_value_string("jsonrpc", "2.0");
182 sharkd_json_value_anyf("id", "%d", id);
183 }
184
185 static void
sharkd_json_response_close(void)186 sharkd_json_response_close(void)
187 {
188 json_dumper_finish(&dumper);
189
190 /*
191 * We do an explicit fflush after every line, because
192 * we want output to be written to the socket as soon
193 * as the line is complete.
194 *
195 * The stream is fully-buffered by default, so it's
196 * only flushed when the buffer fills or the FILE *
197 * is closed. On UN*X, we could set it to be line
198 * buffered, but the MSVC standard I/O routines don't
199 * support line buffering - they only support *byte*
200 * buffering, doing a write for every byte written,
201 * which is too inefficient, and full buffering,
202 * which is what you get if you request line buffering.
203 */
204 fflush(stdout);
205 }
206
207 static void
sharkd_json_result_prologue(guint32 id)208 sharkd_json_result_prologue(guint32 id)
209 {
210 sharkd_json_response_open(id);
211 sharkd_json_value_anyf("result", NULL);
212 json_dumper_begin_object(&dumper); // start the result object
213 }
214
215 static void
sharkd_json_result_epilogue(void)216 sharkd_json_result_epilogue(void)
217 {
218 json_dumper_end_object(&dumper); // end the result object
219 json_dumper_end_object(&dumper); // end the message
220 sharkd_json_response_close();
221 }
222
223 static void
sharkd_json_result_array_prologue(guint32 id)224 sharkd_json_result_array_prologue(guint32 id)
225 {
226 sharkd_json_response_open(id);
227 sharkd_json_array_open("result"); // start the result array
228 }
229
230 static void
sharkd_json_result_array_epilogue(void)231 sharkd_json_result_array_epilogue(void)
232 {
233 sharkd_json_array_close(); // end of result array
234 json_dumper_end_object(&dumper); // end the message
235 sharkd_json_response_close();
236 }
237
238 static void
sharkd_json_simple_ok(guint32 id)239 sharkd_json_simple_ok(guint32 id)
240 {
241 sharkd_json_result_prologue(id);
242 sharkd_json_value_string("status", "OK");
243 sharkd_json_result_epilogue();
244 }
245
246 static void
sharkd_json_warning(guint32 id,char * warning)247 sharkd_json_warning(guint32 id, char *warning)
248 {
249 sharkd_json_result_prologue(id);
250 sharkd_json_value_string("status", "Warning");
251 sharkd_json_value_string("warning", warning);
252 sharkd_json_result_epilogue();
253 }
254
255 static void G_GNUC_PRINTF(4, 5)
sharkd_json_error(guint32 id,int code,char * data,char * format,...)256 sharkd_json_error(guint32 id, int code, char* data, char* format, ...)
257 {
258 sharkd_json_response_open(id);
259 sharkd_json_value_anyf("error", NULL);
260 json_dumper_begin_object(&dumper);
261 sharkd_json_value_anyf("code", "%d", code);
262
263 if (format)
264 {
265 // format the text message
266 va_list args;
267
268 va_start(args, format);
269 char *error_msg = g_strdup_vprintf(format, args);
270 va_end(args);
271
272 sharkd_json_value_string("message", error_msg);
273
274 g_free(error_msg);
275 }
276
277 json_dumper_end_object(&dumper);
278
279 if (data)
280 sharkd_json_value_string("data", data);
281
282 json_dumper_end_object(&dumper);
283 sharkd_json_response_close();
284 }
285
286 static gboolean
is_param_match(const char * param_in,const char * valid_param)287 is_param_match(const char *param_in, const char *valid_param)
288 {
289 char* ptr;
290
291 if ((ptr = g_strrstr(valid_param, "*")))
292 {
293 size_t prefix_len = ptr - valid_param;
294 return !strncmp(param_in, valid_param, prefix_len);
295 }
296 else
297 return !strcmp(param_in, valid_param);
298 }
299
300 /*
301 * json_prep does four things:
302 *
303 * 1. check the syntax of the root and parameter members
304 * 2. tokenize the names and values by zero terminating them
305 * 3. unescape the names and values
306 * 4. extracts and saves the rpcid
307 * - we have to do it here as it's needed for the error messages
308 *
309 * The objective is to minimise the validation work in the functions
310 * that process each called method.
311 *
312 * This gets a little messy as the JSON parser creates a flat list
313 * of all members rather than create a tree.
314 */
315 static gboolean
json_prep(char * buf,const jsmntok_t * tokens,int count)316 json_prep(char* buf, const jsmntok_t* tokens, int count)
317 {
318 int i;
319 char* method = NULL;
320 char* attr_name = NULL;
321 char* attr_value = NULL;
322
323 #define SHARKD_JSON_ANY 0
324 #define SHARKD_JSON_STRING 1
325 #define SHARKD_JSON_INTEGER 2
326 #define SHARKD_JSON_UINTEGER 3
327 #define SHARKD_JSON_FLOAT 4
328 #define SHARKD_JSON_OBJECT 5
329 #define SHARKD_JSON_ARRAY 6
330 #define SHARKD_JSON_BOOLEAN 7
331 #define SHARKD_ARRAY_END 99
332
333 struct member_attribute {
334 const char* parent_ctx;
335 const char* name;
336 int level;
337 jsmntype_t type;
338 int value_type;
339 gboolean is_mandatory;
340 };
341
342 #define MANDATORY TRUE
343 #define OPTIONAL FALSE
344
345 /*
346 * The member attribute structure is key to the syntax checking. The
347 * array contains all of the root level (1) member names, the data
348 * types permissable for the value and a boolean that indicates whether
349 * or not the member is mandatory.
350 *
351 * Once we get into the next layer (2) of the json tree, we need to check
352 * params member names and data types dependent in the context of the method
353 * (parent_ctx).
354 */
355
356 struct member_attribute name_array[] = {
357 // Root members
358 {NULL, "jsonrpc", 1, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY},
359 {NULL, "userid", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
360 {NULL, "id", 1, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, MANDATORY},
361 {NULL, "method", 1, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY},
362 {NULL, "params", 1, JSMN_OBJECT, SHARKD_JSON_OBJECT, OPTIONAL},
363
364 // Valid methods
365 {"method", "analyse", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
366 {"method", "bye", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
367 {"method", "check", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
368 {"method", "complete", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
369 {"method", "download", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
370 {"method", "dumpconf", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
371 {"method", "follow", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
372 {"method", "frame", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
373 {"method", "frames", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
374 {"method", "info", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
375 {"method", "intervals", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
376 {"method", "iograph", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
377 {"method", "load", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
378 {"method", "setcomment", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
379 {"method", "setconf", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
380 {"method", "status", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
381 {"method", "tap", 1, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
382
383 // Parameters and their method context
384 {"check", "field", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
385 {"check", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
386 {"complete", "field", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
387 {"complete", "pref", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
388 {"download", "token", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
389 {"dumpconf", "pref", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
390 {"follow", "follow", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY},
391 {"follow", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY},
392 {"frame", "frame", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, MANDATORY},
393 {"frame", "proto", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL},
394 {"frame", "ref_frame", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL},
395 {"frame", "prev_frame", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL},
396 {"frame", "columns", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL},
397 {"frame", "color", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL},
398 {"frame", "bytes", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL},
399 {"frame", "hidden", 2, JSMN_PRIMITIVE, SHARKD_JSON_BOOLEAN, OPTIONAL},
400 {"frames", "column*", 2, JSMN_UNDEFINED, SHARKD_JSON_ANY, OPTIONAL},
401 {"frames", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
402 {"frames", "skip", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, OPTIONAL},
403 {"frames", "limit", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, OPTIONAL},
404 {"frames", "refs", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
405 {"intervals", "interval", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, OPTIONAL},
406 {"intervals", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
407 {"iograph", "interval", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, OPTIONAL},
408 {"iograph", "filter", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
409 {"iograph", "graph0", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY},
410 {"iograph", "graph1", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
411 {"iograph", "graph2", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
412 {"iograph", "graph3", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
413 {"iograph", "graph4", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
414 {"iograph", "graph5", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
415 {"iograph", "graph6", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
416 {"iograph", "graph7", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
417 {"iograph", "graph8", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
418 {"iograph", "graph9", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
419 {"iograph", "filter0", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
420 {"iograph", "filter1", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
421 {"iograph", "filter2", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
422 {"iograph", "filter3", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
423 {"iograph", "filter4", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
424 {"iograph", "filter5", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
425 {"iograph", "filter6", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
426 {"iograph", "filter7", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
427 {"iograph", "filter8", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
428 {"iograph", "filter9", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
429 {"load", "file", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY},
430 {"setcomment", "frame", 2, JSMN_PRIMITIVE, SHARKD_JSON_UINTEGER, MANDATORY},
431 {"setcomment", "comment", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
432 {"setconf", "name", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY},
433 {"setconf", "value", 2, JSMN_UNDEFINED, SHARKD_JSON_ANY, MANDATORY},
434 {"tap", "tap0", 2, JSMN_STRING, SHARKD_JSON_STRING, MANDATORY},
435 {"tap", "tap1", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
436 {"tap", "tap2", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
437 {"tap", "tap3", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
438 {"tap", "tap4", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
439 {"tap", "tap5", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
440 {"tap", "tap6", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
441 {"tap", "tap7", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
442 {"tap", "tap8", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
443 {"tap", "tap9", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
444 {"tap", "tap10", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
445 {"tap", "tap11", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
446 {"tap", "tap12", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
447 {"tap", "tap13", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
448 {"tap", "tap14", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
449 {"tap", "tap15", 2, JSMN_STRING, SHARKD_JSON_STRING, OPTIONAL},
450
451 // End of the name_array
452 {NULL, NULL, 0, JSMN_STRING, SHARKD_ARRAY_END, OPTIONAL},
453 };
454
455 rpcid = 0;
456
457 /* sanity check, and split strings */
458 if (count < 1 || tokens[0].type != JSMN_OBJECT)
459 {
460 sharkd_json_error(
461 rpcid, -32600, NULL,
462 "The request must an object"
463 );
464 return FALSE;
465 }
466
467 /* don't need [0] token */
468 tokens++;
469 count--;
470
471 if (count & 1)
472 {
473 sharkd_json_error(
474 rpcid, -32600, NULL,
475 "The request must contain name/value pairs"
476 );
477 return FALSE;
478 }
479
480 for (i = 0; i < count; i += 2)
481 {
482 if (tokens[i].type != JSMN_STRING)
483 {
484 sharkd_json_error(
485 rpcid, -32600, NULL,
486 "Member names must be a string - member %d is not string", (i / 2) + 1
487 );
488 return FALSE;
489 }
490
491 buf[tokens[i + 0].end] = '\0';
492 buf[tokens[i + 1].end] = '\0';
493
494 attr_name = &buf[tokens[i + 0].start];
495 attr_value = &buf[tokens[i + 1].start];
496
497 // we must get the id as soon as possible so that it's available in all future error messages
498 if (!strcmp(attr_name, "id"))
499 {
500 if (!ws_strtou32(attr_value, NULL, &rpcid))
501 {
502 sharkd_json_error(
503 rpcid, -32600, NULL,
504 "The id value must be a positive integer"
505 );
506 return FALSE;
507 }
508 }
509
510 if (!strcmp(attr_name, "jsonrpc"))
511 {
512 if (strcmp(&buf[tokens[i + 1].start], "2.0"))
513 {
514 sharkd_json_error(
515 rpcid, -32600, NULL,
516 "Only JSON %s is supported", "2.0"
517 );
518 return FALSE;
519 }
520 }
521
522 /* unescape only value, as keys are simple strings */
523 if (tokens[i + 1].type == JSMN_STRING && !json_decode_string_inplace(attr_value))
524 {
525 sharkd_json_error(
526 rpcid, -32600, NULL,
527 "Cannot unescape the value string of member %d", (i / 2) + 1
528 );
529 return FALSE;
530 }
531
532 /* Confirm that the member is valid */
533 gboolean match = FALSE;
534
535 // We need to check root members (level 1) and parameters (level 2), hence the for loop.
536
537 for (int level = 1; level < 3; level++)
538 {
539 size_t j = 0;
540
541 while (name_array[j].value_type != SHARKD_ARRAY_END) // iterate through the array until we hit the end
542 {
543 if (is_param_match(attr_name, name_array[j].name) && name_array[j].level == level)
544 {
545 // We need to be sure the match is in the correct context
546 // i.e. is this a match for a root member (level 1) or for a parameter (level 2).
547
548 if (level == 1)
549 {
550 // need to guard against a parameter name matching a method name
551 if (method)
552 {
553 if (name_array[j].parent_ctx)
554 {
555 j++;
556 continue;
557 }
558
559 if (!strcmp(method, &buf[tokens[i + 0].start]))
560 {
561 j++;
562 continue;
563 }
564 }
565
566 match = TRUE;
567 }
568 else if (method)
569 {
570 if (level == 2 && !strcmp(name_array[j].parent_ctx, method))
571 match = TRUE;
572 else
573 {
574 j++;
575 continue;
576 }
577 }
578 else
579 {
580 j++;
581 continue;
582 }
583
584 // The match looks good, let's now check the data types
585
586 if (tokens[i + 1].type != name_array[j].type && name_array[j].type != SHARKD_JSON_ANY)
587 {
588 sharkd_json_error(
589 rpcid, -32600, NULL,
590 "The data type for member %s is not a valid", attr_name
591 );
592 return FALSE;
593 }
594 else if (name_array[j].type == JSMN_PRIMITIVE && name_array[j].value_type == SHARKD_JSON_UINTEGER)
595 {
596 guint32 temp;
597 if (!ws_strtou32(attr_value, NULL, &temp) || temp <= 0)
598 {
599 sharkd_json_error(
600 rpcid, -32600, NULL,
601 "The value for %s must be a positive integer", name_array[j].name
602 );
603 return FALSE;
604 }
605 }
606 else if (name_array[j].type == JSMN_PRIMITIVE && name_array[j].value_type == SHARKD_JSON_BOOLEAN)
607 {
608 if (strcmp(attr_value, "true") && strcmp(attr_value, "false"))
609 {
610 sharkd_json_error(
611 rpcid, -32600, NULL,
612 "The value for %s must be a boolean (true or false)", name_array[j].name
613 );
614 return FALSE;
615 }
616
617 }
618 break; // looks like a valid match
619 }
620 j++;
621 }
622
623 if (!strcmp(attr_name, "method"))
624 {
625 int k = 0; // name array index
626 // check that the request method is good
627 while (name_array[k].value_type != SHARKD_ARRAY_END)
628 {
629 if (name_array[k].parent_ctx)
630 {
631 if (!strcmp(attr_value, name_array[k].name) && !strcmp(name_array[k].parent_ctx, "method"))
632 method = attr_value; // the method is valid
633 }
634
635 k++;
636 }
637
638 if (!method)
639 {
640 sharkd_json_error(
641 rpcid, -32601, NULL,
642 "The method %s is not supported", attr_value
643 );
644 return FALSE;
645 }
646 }
647 }
648
649 if (!match)
650 {
651 sharkd_json_error(
652 rpcid, -32600, NULL,
653 "%s is not a valid member name", attr_name
654 );
655 return FALSE;
656 }
657 }
658
659 /* check for mandatory members */
660 size_t j = 0;
661
662 while (name_array[j].value_type != SHARKD_ARRAY_END)
663 {
664 if (name_array[j].is_mandatory && name_array[j].level == 1)
665 {
666 if (!json_find_attr(buf, tokens, count, name_array[j].name))
667 {
668 sharkd_json_error(
669 rpcid, -32600, NULL,
670 "Mandatory member %s is missing", name_array[j].name
671 );
672 return FALSE;
673 }
674 }
675 j++;
676 }
677
678 // check that the current request contains the mandatory parameters
679 j = 0;
680
681 while (name_array[j].value_type != SHARKD_ARRAY_END)
682 {
683 if (name_array[j].is_mandatory && name_array[j].level == 2 && !strcmp(method, name_array[j].parent_ctx))
684 {
685 if (!json_find_attr(buf, tokens, count, name_array[j].name))
686 {
687 sharkd_json_error(
688 rpcid, -32600, NULL,
689 "Mandatory parameter %s is missing", name_array[j].name
690 );
691 return FALSE;
692 }
693 }
694 j++;
695 }
696
697
698 // check that the parameters for the current request are valid for the method and that the data type for the value is valid
699
700 return TRUE;
701 }
702
703 static void
sharkd_session_filter_free(gpointer data)704 sharkd_session_filter_free(gpointer data)
705 {
706 struct sharkd_filter_item *l = (struct sharkd_filter_item *) data;
707
708 g_free(l->filtered);
709 g_free(l);
710 }
711
712 static const struct sharkd_filter_item *
sharkd_session_filter_data(const char * filter)713 sharkd_session_filter_data(const char *filter)
714 {
715 struct sharkd_filter_item *l;
716
717 l = (struct sharkd_filter_item *) g_hash_table_lookup(filter_table, filter);
718 if (!l)
719 {
720 guint8 *filtered = NULL;
721
722 int ret = sharkd_filter(filter, &filtered);
723
724 if (ret == -1)
725 return NULL;
726
727 l = g_new(struct sharkd_filter_item, 1);
728 l->filtered = filtered;
729
730 g_hash_table_insert(filter_table, g_strdup(filter), l);
731 }
732
733 return l;
734 }
735
736 static gboolean
sharkd_rtp_match_init(rtpstream_id_t * id,const char * init_str)737 sharkd_rtp_match_init(rtpstream_id_t *id, const char *init_str)
738 {
739 gboolean ret = FALSE;
740 char **arr;
741 guint32 tmp_addr_src, tmp_addr_dst;
742 address tmp_src_addr, tmp_dst_addr;
743
744 memset(id, 0, sizeof(*id));
745
746 arr = g_strsplit(init_str, "_", 7); /* pass larger value, so we'll catch incorrect input :) */
747 if (g_strv_length(arr) != 5)
748 goto fail;
749
750 /* TODO, for now only IPv4 */
751 if (!get_host_ipaddr(arr[0], &tmp_addr_src))
752 goto fail;
753
754 if (!ws_strtou16(arr[1], NULL, &id->src_port))
755 goto fail;
756
757 if (!get_host_ipaddr(arr[2], &tmp_addr_dst))
758 goto fail;
759
760 if (!ws_strtou16(arr[3], NULL, &id->dst_port))
761 goto fail;
762
763 if (!ws_hexstrtou32(arr[4], NULL, &id->ssrc))
764 goto fail;
765
766 set_address(&tmp_src_addr, AT_IPv4, 4, &tmp_addr_src);
767 copy_address(&id->src_addr, &tmp_src_addr);
768 set_address(&tmp_dst_addr, AT_IPv4, 4, &tmp_addr_dst);
769 copy_address(&id->dst_addr, &tmp_dst_addr);
770
771 ret = TRUE;
772
773 fail:
774 g_strfreev(arr);
775 return ret;
776 }
777
778 static gboolean
sharkd_session_process_info_nstat_cb(const void * key,void * value,void * userdata _U_)779 sharkd_session_process_info_nstat_cb(const void *key, void *value, void *userdata _U_)
780 {
781 stat_tap_table_ui *stat_tap = (stat_tap_table_ui *) value;
782
783 json_dumper_begin_object(&dumper);
784 sharkd_json_value_string("name", stat_tap->title);
785 sharkd_json_value_stringf("tap", "nstat:%s", (const char *) key);
786 json_dumper_end_object(&dumper);
787
788 return FALSE;
789 }
790
791 static gboolean
sharkd_session_process_info_conv_cb(const void * key,void * value,void * userdata _U_)792 sharkd_session_process_info_conv_cb(const void* key, void* value, void* userdata _U_)
793 {
794 struct register_ct *table = (struct register_ct *) value;
795
796 const char *label = (const char *) key;
797
798 if (get_conversation_packet_func(table))
799 {
800 json_dumper_begin_object(&dumper);
801 sharkd_json_value_stringf("name", "Conversation List/%s", label);
802 sharkd_json_value_stringf("tap", "conv:%s", label);
803 json_dumper_end_object(&dumper);
804 }
805
806 if (get_hostlist_packet_func(table))
807 {
808 json_dumper_begin_object(&dumper);
809 sharkd_json_value_stringf("name", "Endpoint/%s", label);
810 sharkd_json_value_stringf("tap", "endpt:%s", label);
811 json_dumper_end_object(&dumper);
812 }
813 return FALSE;
814 }
815
816 static gboolean
sharkd_session_seq_analysis_cb(const void * key,void * value,void * userdata _U_)817 sharkd_session_seq_analysis_cb(const void *key, void *value, void *userdata _U_)
818 {
819 register_analysis_t *analysis = (register_analysis_t *) value;
820
821 json_dumper_begin_object(&dumper);
822 sharkd_json_value_string("name", sequence_analysis_get_ui_name(analysis));
823 sharkd_json_value_stringf("tap", "seqa:%s", (const char *) key);
824 json_dumper_end_object(&dumper);
825
826 return FALSE;
827 }
828
829 static gboolean
sharkd_export_object_visit_cb(const void * key _U_,void * value,void * user_data _U_)830 sharkd_export_object_visit_cb(const void *key _U_, void *value, void *user_data _U_)
831 {
832 register_eo_t *eo = (register_eo_t *) value;
833
834 const int proto_id = get_eo_proto_id(eo);
835 const char *filter = proto_get_protocol_filter_name(proto_id);
836 const char *label = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
837
838 json_dumper_begin_object(&dumper);
839 sharkd_json_value_stringf("name", "Export Object/%s", label);
840 sharkd_json_value_stringf("tap", "eo:%s", filter);
841 json_dumper_end_object(&dumper);
842
843 return FALSE;
844 }
845
846 static gboolean
sharkd_srt_visit_cb(const void * key _U_,void * value,void * user_data _U_)847 sharkd_srt_visit_cb(const void *key _U_, void *value, void *user_data _U_)
848 {
849 register_srt_t *srt = (register_srt_t *) value;
850
851 const int proto_id = get_srt_proto_id(srt);
852 const char *filter = proto_get_protocol_filter_name(proto_id);
853 const char *label = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
854
855 json_dumper_begin_object(&dumper);
856 sharkd_json_value_stringf("name", "Service Response Time/%s", label);
857 sharkd_json_value_stringf("tap", "srt:%s", filter);
858 json_dumper_end_object(&dumper);
859
860 return FALSE;
861 }
862
863 static gboolean
sharkd_rtd_visit_cb(const void * key _U_,void * value,void * user_data _U_)864 sharkd_rtd_visit_cb(const void *key _U_, void *value, void *user_data _U_)
865 {
866 register_rtd_t *rtd = (register_rtd_t *) value;
867
868 const int proto_id = get_rtd_proto_id(rtd);
869 const char *filter = proto_get_protocol_filter_name(proto_id);
870 const char *label = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
871
872 json_dumper_begin_object(&dumper);
873 sharkd_json_value_stringf("name", "Response Time Delay/%s", label);
874 sharkd_json_value_stringf("tap", "rtd:%s", filter);
875 json_dumper_end_object(&dumper);
876
877 return FALSE;
878 }
879
880 static gboolean
sharkd_follower_visit_cb(const void * key _U_,void * value,void * user_data _U_)881 sharkd_follower_visit_cb(const void *key _U_, void *value, void *user_data _U_)
882 {
883 register_follow_t *follower = (register_follow_t *) value;
884
885 const int proto_id = get_follow_proto_id(follower);
886 const char *label = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
887 const char *filter = label; /* correct: get_follow_by_name() is registered by short name */
888
889 json_dumper_begin_object(&dumper);
890 sharkd_json_value_stringf("name", "Follow/%s", label);
891 sharkd_json_value_stringf("tap", "follow:%s", filter);
892 json_dumper_end_object(&dumper);
893
894 return FALSE;
895 }
896
897 /**
898 * sharkd_session_process_info()
899 *
900 * Process info request
901 *
902 * Output object with attributes:
903 * (m) version - version number
904 *
905 * (m) columns - available column formats, array of object with attributes:
906 * 'name' - column name
907 * 'format' - column format-name
908 *
909 * (m) stats - available statistics, array of object with attributes:
910 * 'name' - statistic name
911 * 'tap' - sharkd tap-name for statistic
912 *
913 * (m) convs - available conversation list, array of object with attributes:
914 * 'name' - conversation name
915 * 'tap' - sharkd tap-name for conversation
916 *
917 * (m) eo - available export object list, array of object with attributes:
918 * 'name' - export object name
919 * 'tap' - sharkd tap-name for eo
920 *
921 * (m) srt - available service response time list, array of object with attributes:
922 * 'name' - service response time name
923 * 'tap' - sharkd tap-name for srt
924 *
925 * (m) rtd - available response time delay list, array of object with attributes:
926 * 'name' - response time delay name
927 * 'tap' - sharkd tap-name for rtd
928 *
929 * (m) seqa - available sequence analysis (flow) list, array of object with attributes:
930 * 'name' - sequence analysis name
931 * 'tap' - sharkd tap-name
932 *
933 * (m) taps - available taps, array of object with attributes:
934 * 'name' - tap name
935 * 'tap' - sharkd tap-name
936 *
937 * (m) follow - available followers, array of object with attributes:
938 * 'name' - tap name
939 * 'tap' - sharkd tap-name
940 *
941 * (m) ftypes - conversation table for FT_ number to string, array of FT_xxx strings.
942 *
943 * (m) nstat - available table-based taps, array of object with attributes:
944 * 'name' - tap name
945 * 'tap' - sharkd tap-name
946 *
947 */
948 static void
sharkd_session_process_info(void)949 sharkd_session_process_info(void)
950 {
951 int i;
952
953 sharkd_json_result_prologue(rpcid);
954
955 sharkd_json_array_open("columns");
956 for (i = 0; i < NUM_COL_FMTS; i++)
957 {
958 const char *col_format = col_format_to_string(i);
959 const char *col_descr = col_format_desc(i);
960
961 json_dumper_begin_object(&dumper);
962 sharkd_json_value_string("name", col_descr);
963 sharkd_json_value_string("format", col_format);
964 json_dumper_end_object(&dumper);
965 }
966 sharkd_json_array_close();
967
968 sharkd_json_array_open("stats");
969 {
970 GList *cfg_list = stats_tree_get_cfg_list();
971 GList *l;
972
973 for (l = cfg_list; l; l = l->next)
974 {
975 stats_tree_cfg *cfg = (stats_tree_cfg *) l->data;
976
977 json_dumper_begin_object(&dumper);
978 sharkd_json_value_string("name", cfg->name);
979 sharkd_json_value_stringf("tap", "stat:%s", cfg->abbr);
980 json_dumper_end_object(&dumper);
981 }
982
983 g_list_free(cfg_list);
984 }
985 sharkd_json_array_close();
986
987 sharkd_json_array_open("ftypes");
988 for (i = 0; i < FT_NUM_TYPES; i++)
989 sharkd_json_value_string(NULL, ftype_name((ftenum_t) i));
990 sharkd_json_array_close();
991
992 sharkd_json_value_string("version", get_ws_vcs_version_info_short());
993
994 sharkd_json_array_open("nstat");
995 i = 0;
996 stat_tap_iterate_tables(sharkd_session_process_info_nstat_cb, &i);
997 sharkd_json_array_close();
998
999 sharkd_json_array_open("convs");
1000 i = 0;
1001 conversation_table_iterate_tables(sharkd_session_process_info_conv_cb, &i);
1002 sharkd_json_array_close();
1003
1004 sharkd_json_array_open("seqa");
1005 i = 0;
1006 sequence_analysis_table_iterate_tables(sharkd_session_seq_analysis_cb, &i);
1007 sharkd_json_array_close();
1008
1009 sharkd_json_array_open("taps");
1010 {
1011 json_dumper_begin_object(&dumper);
1012 sharkd_json_value_string("name", "RTP streams");
1013 sharkd_json_value_string("tap", "rtp-streams");
1014 json_dumper_end_object(&dumper);
1015
1016 json_dumper_begin_object(&dumper);
1017 sharkd_json_value_string("name", "Expert Information");
1018 sharkd_json_value_string("tap", "expert");
1019 json_dumper_end_object(&dumper);
1020 }
1021 sharkd_json_array_close();
1022
1023 sharkd_json_array_open("eo");
1024 i = 0;
1025 eo_iterate_tables(sharkd_export_object_visit_cb, &i);
1026 sharkd_json_array_close();
1027
1028 sharkd_json_array_open("srt");
1029 i = 0;
1030 srt_table_iterate_tables(sharkd_srt_visit_cb, &i);
1031 sharkd_json_array_close();
1032
1033 sharkd_json_array_open("rtd");
1034 i = 0;
1035 rtd_table_iterate_tables(sharkd_rtd_visit_cb, &i);
1036 sharkd_json_array_close();
1037
1038 sharkd_json_array_open("follow");
1039 i = 0;
1040 follow_iterate_followers(sharkd_follower_visit_cb, &i);
1041 sharkd_json_array_close();
1042
1043 sharkd_json_result_epilogue();
1044 }
1045
1046 /**
1047 * sharkd_session_process_load()
1048 *
1049 * Process load request
1050 *
1051 * Input:
1052 * (m) file - file to be loaded
1053 *
1054 * Output object with attributes:
1055 * (m) err - error code
1056 */
1057 static void
sharkd_session_process_load(const char * buf,const jsmntok_t * tokens,int count)1058 sharkd_session_process_load(const char *buf, const jsmntok_t *tokens, int count)
1059 {
1060 const char *tok_file = json_find_attr(buf, tokens, count, "file");
1061 int err = 0;
1062
1063 if (!tok_file)
1064 return;
1065
1066 fprintf(stderr, "load: filename=%s\n", tok_file);
1067
1068 if (sharkd_cf_open(tok_file, WTAP_TYPE_AUTO, FALSE, &err) != CF_OK)
1069 {
1070 sharkd_json_error(
1071 rpcid, -2001, NULL,
1072 "Unable to open the file"
1073 );
1074 return;
1075 }
1076
1077 TRY
1078 {
1079 err = sharkd_load_cap_file();
1080 }
1081 CATCH(OutOfMemoryError)
1082 {
1083 sharkd_json_error(
1084 rpcid, -32603, NULL,
1085 "Load failed, out of memory"
1086 );
1087 fprintf(stderr, "load: OutOfMemoryError\n");
1088 err = ENOMEM;
1089 }
1090 ENDTRY;
1091
1092 if (err == 0)
1093 sharkd_json_simple_ok(rpcid);
1094 }
1095
1096 /**
1097 * sharkd_session_process_status()
1098 *
1099 * Process status request
1100 *
1101 * Output object with attributes:
1102 * (m) frames - count of currently loaded frames
1103 * (m) duration - time difference between time of first frame, and last loaded frame
1104 * (o) filename - capture filename
1105 * (o) filesize - capture filesize
1106 */
1107 static void
sharkd_session_process_status(void)1108 sharkd_session_process_status(void)
1109 {
1110 sharkd_json_result_prologue(rpcid);
1111
1112 sharkd_json_value_anyf("frames", "%u", cfile.count);
1113 sharkd_json_value_anyf("duration", "%.9f", nstime_to_sec(&cfile.elapsed_time));
1114
1115 if (cfile.filename)
1116 {
1117 char *name = g_path_get_basename(cfile.filename);
1118
1119 sharkd_json_value_string("filename", name);
1120 g_free(name);
1121 }
1122
1123 if (cfile.provider.wth)
1124 {
1125 gint64 file_size = wtap_file_size(cfile.provider.wth, NULL);
1126
1127 if (file_size > 0)
1128 sharkd_json_value_anyf("filesize", "%" G_GINT64_FORMAT, file_size);
1129 }
1130
1131 sharkd_json_result_epilogue();
1132 }
1133
1134 struct sharkd_analyse_data
1135 {
1136 GHashTable *protocols_set;
1137 nstime_t *first_time;
1138 nstime_t *last_time;
1139 };
1140
1141 static void
sharkd_session_process_analyse_cb(epan_dissect_t * edt,proto_tree * tree _U_,struct epan_column_info * cinfo _U_,const GSList * data_src _U_,void * data)1142 sharkd_session_process_analyse_cb(epan_dissect_t *edt, proto_tree *tree _U_,
1143 struct epan_column_info *cinfo _U_, const GSList *data_src _U_, void *data)
1144 {
1145 struct sharkd_analyse_data *analyser = (struct sharkd_analyse_data *) data;
1146 packet_info *pi = &edt->pi;
1147 frame_data *fdata = pi->fd;
1148
1149 if (analyser->first_time == NULL || nstime_cmp(&fdata->abs_ts, analyser->first_time) < 0)
1150 analyser->first_time = &fdata->abs_ts;
1151
1152 if (analyser->last_time == NULL || nstime_cmp(&fdata->abs_ts, analyser->last_time) > 0)
1153 analyser->last_time = &fdata->abs_ts;
1154
1155 if (pi->layers)
1156 {
1157 wmem_list_frame_t *frame;
1158
1159 for (frame = wmem_list_head(pi->layers); frame; frame = wmem_list_frame_next(frame))
1160 {
1161 int proto_id = GPOINTER_TO_UINT(wmem_list_frame_data(frame));
1162
1163 if (!g_hash_table_lookup_extended(analyser->protocols_set, GUINT_TO_POINTER(proto_id), NULL, NULL))
1164 {
1165 g_hash_table_insert(analyser->protocols_set, GUINT_TO_POINTER(proto_id), GUINT_TO_POINTER(proto_id));
1166 sharkd_json_value_string(NULL, proto_get_protocol_filter_name(proto_id));
1167 }
1168 }
1169 }
1170
1171 }
1172
1173 /**
1174 * sharkd_session_process_status()
1175 *
1176 * Process analyse request
1177 *
1178 * Output object with attributes:
1179 * (m) frames - count of currently loaded frames
1180 * (m) protocols - protocol list
1181 * (m) first - earliest frame time
1182 * (m) last - latest frame time
1183 */
1184 static void
sharkd_session_process_analyse(void)1185 sharkd_session_process_analyse(void)
1186 {
1187 struct sharkd_analyse_data analyser;
1188 wtap_rec rec; /* Record metadata */
1189 Buffer rec_buf; /* Record data */
1190
1191 analyser.first_time = NULL;
1192 analyser.last_time = NULL;
1193 analyser.protocols_set = g_hash_table_new(NULL /* g_direct_hash() */, NULL /* g_direct_equal */);
1194
1195 sharkd_json_result_prologue(rpcid);
1196
1197 sharkd_json_value_anyf("frames", "%u", cfile.count);
1198
1199 sharkd_json_array_open("protocols");
1200
1201 wtap_rec_init(&rec);
1202 ws_buffer_init(&rec_buf, 1514);
1203
1204 for (guint32 framenum = 1; framenum <= cfile.count; framenum++)
1205 {
1206 enum dissect_request_status status;
1207 int err;
1208 gchar *err_info;
1209
1210 status = sharkd_dissect_request(framenum,
1211 (framenum != 1) ? 1 : 0, framenum - 1,
1212 &rec, &rec_buf, NULL, SHARKD_DISSECT_FLAG_NULL,
1213 &sharkd_session_process_analyse_cb, &analyser,
1214 &err, &err_info);
1215 switch (status) {
1216
1217 case DISSECT_REQUEST_SUCCESS:
1218 break;
1219
1220 case DISSECT_REQUEST_NO_SUCH_FRAME:
1221 /* XXX - report the error. */
1222 break;
1223
1224 case DISSECT_REQUEST_READ_ERROR:
1225 /*
1226 * Free up the error string.
1227 * XXX - report the error.
1228 */
1229 g_free(err_info);
1230 break;
1231 }
1232 }
1233
1234 sharkd_json_array_close();
1235
1236 if (analyser.first_time)
1237 sharkd_json_value_anyf("first", "%.9f", nstime_to_sec(analyser.first_time));
1238
1239 if (analyser.last_time)
1240 sharkd_json_value_anyf("last", "%.9f", nstime_to_sec(analyser.last_time));
1241
1242 sharkd_json_result_epilogue();
1243
1244 wtap_rec_cleanup(&rec);
1245 ws_buffer_free(&rec_buf);
1246
1247 g_hash_table_destroy(analyser.protocols_set);
1248 }
1249
1250 static column_info *
sharkd_session_create_columns(column_info * cinfo,const char * buf,const jsmntok_t * tokens,int count)1251 sharkd_session_create_columns(column_info *cinfo, const char *buf, const jsmntok_t *tokens, int count)
1252 {
1253 const char *columns_custom[32];
1254 guint16 columns_fmt[32];
1255 gint16 columns_occur[32];
1256
1257 int i, cols;
1258
1259 for (i = 0; i < 32; i++)
1260 {
1261 const char *tok_column;
1262 char tok_column_name[64];
1263 char *custom_sepa;
1264
1265 snprintf(tok_column_name, sizeof(tok_column_name), "column%d", i);
1266 tok_column = json_find_attr(buf, tokens, count, tok_column_name);
1267 if (tok_column == NULL)
1268 break;
1269
1270 columns_custom[i] = NULL;
1271 columns_occur[i] = 0;
1272
1273 if ((custom_sepa = strchr(tok_column, ':')))
1274 {
1275 *custom_sepa = '\0'; /* XXX, C abuse: discarding-const */
1276
1277 columns_fmt[i] = COL_CUSTOM;
1278 columns_custom[i] = tok_column;
1279
1280 if (!ws_strtoi16(custom_sepa + 1, NULL, &columns_occur[i]))
1281 return NULL;
1282 }
1283 else
1284 {
1285 if (!ws_strtou16(tok_column, NULL, &columns_fmt[i]))
1286 return NULL;
1287
1288 if (columns_fmt[i] >= NUM_COL_FMTS)
1289 return NULL;
1290
1291 /* if custom, that it shouldn't be just custom number -> error */
1292 if (columns_fmt[i] == COL_CUSTOM)
1293 return NULL;
1294 }
1295 }
1296
1297 cols = i;
1298
1299 col_setup(cinfo, cols);
1300
1301 for (i = 0; i < cols; i++)
1302 {
1303 col_item_t *col_item = &cinfo->columns[i];
1304
1305 col_item->col_fmt = columns_fmt[i];
1306 col_item->col_title = NULL; /* no need for title */
1307
1308 if (col_item->col_fmt == COL_CUSTOM)
1309 {
1310 col_item->col_custom_fields = g_strdup(columns_custom[i]);
1311 col_item->col_custom_occurrence = columns_occur[i];
1312 }
1313
1314 col_item->col_fence = 0;
1315 }
1316
1317 col_finalize(cinfo);
1318
1319 return cinfo;
1320 }
1321
1322 static void
sharkd_session_process_frames_cb(epan_dissect_t * edt,proto_tree * tree _U_,struct epan_column_info * cinfo,const GSList * data_src _U_,void * data _U_)1323 sharkd_session_process_frames_cb(epan_dissect_t *edt, proto_tree *tree _U_,
1324 struct epan_column_info *cinfo, const GSList *data_src _U_, void *data _U_)
1325 {
1326 packet_info *pi = &edt->pi;
1327 frame_data *fdata = pi->fd;
1328 wtap_block_t pkt_block = NULL;
1329 char *comment;
1330
1331 json_dumper_begin_object(&dumper);
1332
1333 sharkd_json_array_open("c");
1334 for (int col = 0; col < cinfo->num_cols; ++col)
1335 {
1336 const col_item_t *col_item = &cinfo->columns[col];
1337
1338 sharkd_json_value_string(NULL, col_item->col_data);
1339 }
1340 sharkd_json_array_close();
1341
1342 sharkd_json_value_anyf("num", "%u", pi->num);
1343
1344 /*
1345 * Get the block for this record, if it has one.
1346 */
1347 if (fdata->has_modified_block)
1348 pkt_block = sharkd_get_modified_block(fdata);
1349 else
1350 pkt_block = pi->rec->block;
1351
1352 /*
1353 * Does this record have any comments?
1354 */
1355 if (pkt_block != NULL &&
1356 WTAP_OPTTYPE_SUCCESS == wtap_block_get_nth_string_option_value(pkt_block, OPT_COMMENT, 0, &comment))
1357 sharkd_json_value_anyf("ct", "true");
1358
1359 if (fdata->ignored)
1360 sharkd_json_value_anyf("i", "true");
1361
1362 if (fdata->marked)
1363 sharkd_json_value_anyf("m", "true");
1364
1365 if (fdata->color_filter)
1366 {
1367 sharkd_json_value_stringf("bg", "%x", color_t_to_rgb(&fdata->color_filter->bg_color));
1368 sharkd_json_value_stringf("fg", "%x", color_t_to_rgb(&fdata->color_filter->fg_color));
1369 }
1370
1371 json_dumper_end_object(&dumper);
1372 }
1373
1374 /**
1375 * sharkd_session_process_frames()
1376 *
1377 * Process frames request
1378 *
1379 * Input:
1380 * (o) column0...columnXX - requested columns either number in range [0..NUM_COL_FMTS), or custom (syntax <dfilter>:<occurence>).
1381 * If column0 is not specified default column set will be used.
1382 * (o) filter - filter to be used
1383 * (o) skip=N - skip N frames
1384 * (o) limit=N - show only N frames
1385 * (o) refs - list (comma separated) with sorted time reference frame numbers.
1386 *
1387 * Output array of frames with attributes:
1388 * (m) c - array of column data
1389 * (m) num - frame number
1390 * (o) i - if frame is ignored
1391 * (o) m - if frame is marked
1392 * (o) ct - if frame is commented
1393 * (o) bg - color filter - background color in hex
1394 * (o) fg - color filter - foreground color in hex
1395 */
1396 static void
sharkd_session_process_frames(const char * buf,const jsmntok_t * tokens,int count)1397 sharkd_session_process_frames(const char *buf, const jsmntok_t *tokens, int count)
1398 {
1399 const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
1400 const char *tok_column = json_find_attr(buf, tokens, count, "column0");
1401 const char *tok_skip = json_find_attr(buf, tokens, count, "skip");
1402 const char *tok_limit = json_find_attr(buf, tokens, count, "limit");
1403 const char *tok_refs = json_find_attr(buf, tokens, count, "refs");
1404
1405 const guint8 *filter_data = NULL;
1406
1407 guint32 next_ref_frame = G_MAXUINT32;
1408 guint32 skip;
1409 guint32 limit;
1410
1411 wtap_rec rec; /* Record metadata */
1412 Buffer rec_buf; /* Record data */
1413 column_info *cinfo = &cfile.cinfo;
1414 column_info user_cinfo;
1415
1416 if (tok_column)
1417 {
1418 memset(&user_cinfo, 0, sizeof(user_cinfo));
1419 cinfo = sharkd_session_create_columns(&user_cinfo, buf, tokens, count);
1420 if (!cinfo)
1421 {
1422 sharkd_json_error(
1423 rpcid, -13001, NULL,
1424 "Column definition invalid - note column 6 requires a custom definition"
1425 );
1426 return;
1427 }
1428 }
1429
1430 if (tok_filter)
1431 {
1432 const struct sharkd_filter_item *filter_item;
1433
1434 filter_item = sharkd_session_filter_data(tok_filter);
1435 if (!filter_item)
1436 {
1437 sharkd_json_error(
1438 rpcid, -13002, NULL,
1439 "Filter expression invalid"
1440 );
1441 return;
1442 }
1443
1444 filter_data = filter_item->filtered;
1445 }
1446
1447 skip = 0;
1448 if (tok_skip)
1449 {
1450 if (!ws_strtou32(tok_skip, NULL, &skip))
1451 return;
1452 }
1453
1454 limit = 0;
1455 if (tok_limit)
1456 {
1457 if (!ws_strtou32(tok_limit, NULL, &limit))
1458 return;
1459 }
1460
1461 if (tok_refs)
1462 {
1463 if (!ws_strtou32(tok_refs, &tok_refs, &next_ref_frame))
1464 return;
1465 }
1466
1467 sharkd_json_result_array_prologue(rpcid);
1468
1469 wtap_rec_init(&rec);
1470 ws_buffer_init(&rec_buf, 1514);
1471
1472 for (guint32 framenum = 1; framenum <= cfile.count; framenum++)
1473 {
1474 frame_data *fdata;
1475 enum dissect_request_status status;
1476 int err;
1477 gchar *err_info;
1478
1479 if (filter_data && !(filter_data[framenum / 8] & (1 << (framenum % 8))))
1480 continue;
1481
1482 if (skip)
1483 {
1484 skip--;
1485 continue;
1486 }
1487
1488 if (tok_refs)
1489 {
1490 if (framenum >= next_ref_frame)
1491 {
1492 if (*tok_refs != ',')
1493 next_ref_frame = G_MAXUINT32;
1494
1495 while (*tok_refs == ',' && framenum >= next_ref_frame)
1496 {
1497 if (!ws_strtou32(tok_refs + 1, &tok_refs, &next_ref_frame))
1498 {
1499 fprintf(stderr, "sharkd_session_process_frames() wrong format for refs: %s\n", tok_refs);
1500 break;
1501 }
1502 }
1503
1504 if (*tok_refs == '\0' && framenum >= next_ref_frame)
1505 {
1506 next_ref_frame = G_MAXUINT32;
1507 }
1508 }
1509 }
1510
1511 fdata = sharkd_get_frame(framenum);
1512 status = sharkd_dissect_request(framenum,
1513 (framenum != 1) ? 1 : 0, framenum - 1,
1514 &rec, &rec_buf, cinfo,
1515 (fdata->color_filter == NULL) ? SHARKD_DISSECT_FLAG_COLOR : SHARKD_DISSECT_FLAG_NULL,
1516 &sharkd_session_process_frames_cb, NULL,
1517 &err, &err_info);
1518 switch (status) {
1519
1520 case DISSECT_REQUEST_SUCCESS:
1521 break;
1522
1523 case DISSECT_REQUEST_NO_SUCH_FRAME:
1524 /* XXX - report the error. */
1525 break;
1526
1527 case DISSECT_REQUEST_READ_ERROR:
1528 /*
1529 * Free up the error string.
1530 * XXX - report the error.
1531 */
1532 g_free(err_info);
1533 break;
1534 }
1535
1536 if (limit && --limit == 0)
1537 break;
1538 }
1539 sharkd_json_result_array_epilogue();
1540
1541 if (cinfo != &cfile.cinfo)
1542 col_cleanup(cinfo);
1543
1544 wtap_rec_cleanup(&rec);
1545 ws_buffer_free(&rec_buf);
1546 }
1547
1548 static void
sharkd_session_process_tap_stats_node_cb(const stat_node * n)1549 sharkd_session_process_tap_stats_node_cb(const stat_node *n)
1550 {
1551 stat_node *node;
1552
1553 sharkd_json_array_open(NULL);
1554 for (node = n->children; node; node = node->next)
1555 {
1556 json_dumper_begin_object(&dumper);
1557
1558 /* code based on stats_tree_get_values_from_node() */
1559 sharkd_json_value_string("name", node->name);
1560 sharkd_json_value_anyf("count", "%d", node->counter);
1561 if (node->counter && ((node->st_flags & ST_FLG_AVERAGE) || node->rng))
1562 {
1563 switch(node->datatype)
1564 {
1565 case STAT_DT_INT:
1566 sharkd_json_value_anyf("avg", "%.2f", ((float)node->total.int_total) / node->counter);
1567 sharkd_json_value_anyf("min", "%d", node->minvalue.int_min);
1568 sharkd_json_value_anyf("max", "%d", node->maxvalue.int_max);
1569 break;
1570 case STAT_DT_FLOAT:
1571 sharkd_json_value_anyf("avg", "%.2f", node->total.float_total / node->counter);
1572 sharkd_json_value_anyf("min", "%f", node->minvalue.float_min);
1573 sharkd_json_value_anyf("max", "%f", node->maxvalue.float_max);
1574 break;
1575 }
1576 }
1577
1578 if (node->st->elapsed)
1579 sharkd_json_value_anyf("rate", "%.4f", ((float)node->counter) / node->st->elapsed);
1580
1581 if (node->parent && node->parent->counter)
1582 sharkd_json_value_anyf("perc", "%.2f", (node->counter * 100.0) / node->parent->counter);
1583 else if (node->parent == &(node->st->root))
1584 sharkd_json_value_anyf("perc", "100");
1585
1586 if (prefs.st_enable_burstinfo && node->max_burst)
1587 {
1588 if (prefs.st_burst_showcount)
1589 sharkd_json_value_anyf("burstcount", "%d", node->max_burst);
1590 else
1591 sharkd_json_value_anyf("burstrate", "%.4f", ((double)node->max_burst) / prefs.st_burst_windowlen);
1592
1593 sharkd_json_value_anyf("bursttime", "%.3f", (node->burst_time / 1000.0));
1594 }
1595
1596 if (node->children)
1597 {
1598 sharkd_json_value_anyf("sub", NULL);
1599 sharkd_session_process_tap_stats_node_cb(node);
1600 }
1601 json_dumper_end_object(&dumper);
1602 }
1603 sharkd_json_array_close();
1604 }
1605
1606 /**
1607 * sharkd_session_process_tap_stats_cb()
1608 *
1609 * Output stats tap:
1610 *
1611 * (m) tap - tap name
1612 * (m) type:stats - tap output type
1613 * (m) name - stat name
1614 * (m) stats - array of object with attributes:
1615 * (m) name - stat item name
1616 * (m) count - stat item counter
1617 * (o) avg - stat item averange value
1618 * (o) min - stat item min value
1619 * (o) max - stat item max value
1620 * (o) rate - stat item rate value (ms)
1621 * (o) perc - stat item percentage
1622 * (o) burstrate - stat item burst rate
1623 * (o) burstcount - stat item burst count
1624 * (o) burstttme - stat item burst start
1625 * (o) sub - array of object with attributes like in stats node.
1626 */
1627 static void
sharkd_session_process_tap_stats_cb(void * psp)1628 sharkd_session_process_tap_stats_cb(void *psp)
1629 {
1630 stats_tree *st = (stats_tree *) psp;
1631
1632 json_dumper_begin_object(&dumper);
1633
1634 sharkd_json_value_stringf("tap", "stats:%s", st->cfg->abbr);
1635 sharkd_json_value_string("type", "stats");
1636 sharkd_json_value_string("name", st->cfg->name);
1637
1638 sharkd_json_value_anyf("stats", NULL);
1639 sharkd_session_process_tap_stats_node_cb(&st->root);
1640
1641 json_dumper_end_object(&dumper);
1642 }
1643
1644 static void
sharkd_session_free_tap_stats_cb(void * psp)1645 sharkd_session_free_tap_stats_cb(void *psp)
1646 {
1647 stats_tree *st = (stats_tree *) psp;
1648
1649 stats_tree_free(st);
1650 }
1651
1652 struct sharkd_expert_tap
1653 {
1654 GSList *details;
1655 GStringChunk *text;
1656 };
1657
1658 /**
1659 * sharkd_session_process_tap_expert_cb()
1660 *
1661 * Output expert tap:
1662 *
1663 * (m) tap - tap name
1664 * (m) type:expert - tap output type
1665 * (m) details - array of object with attributes:
1666 * (m) f - frame number, which generated expert information
1667 * (o) s - severity
1668 * (o) g - group
1669 * (m) m - expert message
1670 * (o) p - protocol
1671 */
1672 static void
sharkd_session_process_tap_expert_cb(void * tapdata)1673 sharkd_session_process_tap_expert_cb(void *tapdata)
1674 {
1675 struct sharkd_expert_tap *etd = (struct sharkd_expert_tap *) tapdata;
1676 GSList *list;
1677
1678 json_dumper_begin_object(&dumper);
1679
1680 sharkd_json_value_string("tap", "expert");
1681 sharkd_json_value_string("type", "expert");
1682
1683 sharkd_json_array_open("details");
1684 for (list = etd->details; list; list = list->next)
1685 {
1686 expert_info_t *ei = (expert_info_t *) list->data;
1687 const char *tmp;
1688
1689 json_dumper_begin_object(&dumper);
1690
1691 sharkd_json_value_anyf("f", "%u", ei->packet_num);
1692
1693 tmp = try_val_to_str(ei->severity, expert_severity_vals);
1694 if (tmp)
1695 sharkd_json_value_string("s", tmp);
1696
1697 tmp = try_val_to_str(ei->group, expert_group_vals);
1698 if (tmp)
1699 sharkd_json_value_string("g", tmp);
1700
1701 sharkd_json_value_string("m", ei->summary);
1702
1703 if (ei->protocol)
1704 sharkd_json_value_string("p", ei->protocol);
1705
1706 json_dumper_end_object(&dumper);
1707 }
1708 sharkd_json_array_close();
1709
1710 json_dumper_end_object(&dumper);
1711 }
1712
1713 static tap_packet_status
sharkd_session_packet_tap_expert_cb(void * tapdata,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * pointer)1714 sharkd_session_packet_tap_expert_cb(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pointer)
1715 {
1716 struct sharkd_expert_tap *etd = (struct sharkd_expert_tap *) tapdata;
1717 const expert_info_t *ei = (const expert_info_t *) pointer;
1718 expert_info_t *ei_copy;
1719
1720 if (ei == NULL)
1721 return TAP_PACKET_DONT_REDRAW;
1722
1723 ei_copy = g_new(expert_info_t, 1);
1724 /* Note: this is a shallow copy */
1725 *ei_copy = *ei;
1726
1727 /* ei->protocol, ei->summary might be allocated in packet scope, make a copy. */
1728 ei_copy->protocol = g_string_chunk_insert_const(etd->text, ei_copy->protocol);
1729 ei_copy->summary = g_string_chunk_insert_const(etd->text, ei_copy->summary);
1730
1731 etd->details = g_slist_prepend(etd->details, ei_copy);
1732
1733 return TAP_PACKET_REDRAW;
1734 }
1735
1736 static void
sharkd_session_free_tap_expert_cb(void * tapdata)1737 sharkd_session_free_tap_expert_cb(void *tapdata)
1738 {
1739 struct sharkd_expert_tap *etd = (struct sharkd_expert_tap *) tapdata;
1740
1741 g_slist_free_full(etd->details, g_free);
1742 g_string_chunk_free(etd->text);
1743 g_free(etd);
1744 }
1745
1746 /**
1747 * sharkd_session_process_tap_flow_cb()
1748 *
1749 * Output flow tap:
1750 * (m) tap - tap name
1751 * (m) type:flow - tap output type
1752 * (m) nodes - array of strings with node address
1753 * (m) flows - array of object with attributes:
1754 * (m) t - frame time string
1755 * (m) n - array of two numbers with source node index and destination node index
1756 * (m) pn - array of two numbers with source and destination port
1757 * (o) c - comment
1758 */
1759 static void
sharkd_session_process_tap_flow_cb(void * tapdata)1760 sharkd_session_process_tap_flow_cb(void *tapdata)
1761 {
1762 seq_analysis_info_t *graph_analysis = (seq_analysis_info_t *) tapdata;
1763 GList *flow_list;
1764 guint i;
1765
1766 sequence_analysis_get_nodes(graph_analysis);
1767
1768 json_dumper_begin_object(&dumper);
1769 sharkd_json_value_stringf("tap", "seqa:%s", graph_analysis->name);
1770 sharkd_json_value_string("type", "flow");
1771
1772 sharkd_json_array_open("nodes");
1773 for (i = 0; i < graph_analysis->num_nodes; i++)
1774 {
1775 char *addr_str;
1776
1777 addr_str = address_to_display(NULL, &(graph_analysis->nodes[i]));
1778 sharkd_json_value_string(NULL, addr_str);
1779 wmem_free(NULL, addr_str);
1780 }
1781 sharkd_json_array_close();
1782
1783 sharkd_json_array_open("flows");
1784 flow_list = g_queue_peek_nth_link(graph_analysis->items, 0);
1785 while (flow_list)
1786 {
1787 seq_analysis_item_t *sai = (seq_analysis_item_t *) flow_list->data;
1788
1789 flow_list = g_list_next(flow_list);
1790
1791 if (!sai->display)
1792 continue;
1793
1794 json_dumper_begin_object(&dumper);
1795
1796 sharkd_json_value_string("t", sai->time_str);
1797 sharkd_json_value_anyf("n", "[%u,%u]", sai->src_node, sai->dst_node);
1798 sharkd_json_value_anyf("pn", "[%u,%u]", sai->port_src, sai->port_dst);
1799
1800 if (sai->comment)
1801 sharkd_json_value_string("c", sai->comment);
1802
1803 json_dumper_end_object(&dumper);
1804 }
1805 sharkd_json_array_close();
1806
1807 json_dumper_end_object(&dumper);
1808 }
1809
1810 static void
sharkd_session_free_tap_flow_cb(void * tapdata)1811 sharkd_session_free_tap_flow_cb(void *tapdata)
1812 {
1813 seq_analysis_info_t *graph_analysis = (seq_analysis_info_t *) tapdata;
1814
1815 sequence_analysis_info_free(graph_analysis);
1816 }
1817
1818 struct sharkd_conv_tap_data
1819 {
1820 const char *type;
1821 conv_hash_t hash;
1822 gboolean resolve_name;
1823 gboolean resolve_port;
1824 };
1825
1826 static gboolean
sharkd_session_geoip_addr(address * addr,const char * suffix)1827 sharkd_session_geoip_addr(address *addr, const char *suffix)
1828 {
1829 const mmdb_lookup_t *lookup = NULL;
1830 gboolean with_geoip = FALSE;
1831 char json_key[64];
1832
1833 if (addr->type == AT_IPv4)
1834 {
1835 const ws_in4_addr *ip4 = (const ws_in4_addr *) addr->data;
1836
1837 lookup = maxmind_db_lookup_ipv4(ip4);
1838 }
1839 else if (addr->type == AT_IPv6)
1840 {
1841 const ws_in6_addr *ip6 = (const ws_in6_addr *) addr->data;
1842
1843 lookup = maxmind_db_lookup_ipv6(ip6);
1844 }
1845
1846 if (!lookup || !lookup->found)
1847 return FALSE;
1848
1849 if (lookup->country)
1850 {
1851 snprintf(json_key, sizeof(json_key), "geoip_country%s", suffix);
1852 sharkd_json_value_string(json_key, lookup->country);
1853 with_geoip = TRUE;
1854 }
1855
1856 if (lookup->country_iso)
1857 {
1858 snprintf(json_key, sizeof(json_key), "geoip_country_iso%s", suffix);
1859 sharkd_json_value_string(json_key, lookup->country_iso);
1860 with_geoip = TRUE;
1861 }
1862
1863 if (lookup->city)
1864 {
1865 snprintf(json_key, sizeof(json_key), "geoip_city%s", suffix);
1866 sharkd_json_value_string(json_key, lookup->city);
1867 with_geoip = TRUE;
1868 }
1869
1870 if (lookup->as_org)
1871 {
1872 snprintf(json_key, sizeof(json_key), "geoip_as_org%s", suffix);
1873 sharkd_json_value_string(json_key, lookup->as_org);
1874 with_geoip = TRUE;
1875 }
1876
1877 if (lookup->as_number > 0)
1878 {
1879 snprintf(json_key, sizeof(json_key), "geoip_as%s", suffix);
1880 sharkd_json_value_anyf(json_key, "%u", lookup->as_number);
1881 with_geoip = TRUE;
1882 }
1883
1884 if (lookup->latitude >= -90.0 && lookup->latitude <= 90.0)
1885 {
1886 snprintf(json_key, sizeof(json_key), "geoip_lat%s", suffix);
1887 sharkd_json_value_anyf(json_key, "%f", lookup->latitude);
1888 with_geoip = TRUE;
1889 }
1890
1891 if (lookup->longitude >= -180.0 && lookup->longitude <= 180.0)
1892 {
1893 snprintf(json_key, sizeof(json_key), "geoip_lon%s", suffix);
1894 sharkd_json_value_anyf(json_key, "%f", lookup->longitude);
1895 with_geoip = TRUE;
1896 }
1897
1898 return with_geoip;
1899 }
1900
1901 struct sharkd_analyse_rtp_items
1902 {
1903 guint32 frame_num;
1904 guint32 sequence_num;
1905
1906 double delta;
1907 double jitter;
1908 double skew;
1909 double bandwidth;
1910 gboolean marker;
1911
1912 double arrive_offset;
1913
1914 /* from tap_rtp_stat_t */
1915 guint32 flags;
1916 guint16 pt;
1917 };
1918
1919 struct sharkd_analyse_rtp
1920 {
1921 const char *tap_name;
1922 rtpstream_id_t id;
1923
1924 GSList *packets;
1925 double start_time;
1926 tap_rtp_stat_t statinfo;
1927 };
1928
1929 static void
sharkd_session_process_tap_rtp_free_cb(void * tapdata)1930 sharkd_session_process_tap_rtp_free_cb(void *tapdata)
1931 {
1932 struct sharkd_analyse_rtp *rtp_req = (struct sharkd_analyse_rtp *) tapdata;
1933
1934 g_slist_free_full(rtp_req->packets, g_free);
1935 g_free(rtp_req);
1936 }
1937
1938 static tap_packet_status
sharkd_session_packet_tap_rtp_analyse_cb(void * tapdata,packet_info * pinfo,epan_dissect_t * edt _U_,const void * pointer)1939 sharkd_session_packet_tap_rtp_analyse_cb(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pointer)
1940 {
1941 struct sharkd_analyse_rtp *rtp_req = (struct sharkd_analyse_rtp *) tapdata;
1942 const struct _rtp_info *rtp_info = (const struct _rtp_info *) pointer;
1943
1944 if (rtpstream_id_equal_pinfo_rtp_info(&rtp_req->id, pinfo, rtp_info))
1945 {
1946 tap_rtp_stat_t *statinfo = &(rtp_req->statinfo);
1947 struct sharkd_analyse_rtp_items *item;
1948
1949 rtppacket_analyse(statinfo, pinfo, rtp_info);
1950
1951 item = g_new(struct sharkd_analyse_rtp_items, 1);
1952
1953 if (!rtp_req->packets)
1954 rtp_req->start_time = nstime_to_sec(&pinfo->abs_ts);
1955
1956 item->frame_num = pinfo->num;
1957 item->sequence_num = rtp_info->info_seq_num;
1958 item->delta = (statinfo->flags & STAT_FLAG_FIRST) ? 0.0 : statinfo->delta;
1959 item->jitter = (statinfo->flags & STAT_FLAG_FIRST) ? 0.0 : statinfo->jitter;
1960 item->skew = (statinfo->flags & STAT_FLAG_FIRST) ? 0.0 : statinfo->skew;
1961 item->bandwidth = statinfo->bandwidth;
1962 item->marker = rtp_info->info_marker_set ? TRUE : FALSE;
1963 item->arrive_offset= nstime_to_sec(&pinfo->abs_ts) - rtp_req->start_time;
1964
1965 item->flags = statinfo->flags;
1966 item->pt = statinfo->pt;
1967
1968 /* XXX, O(n) optimize */
1969 rtp_req->packets = g_slist_append(rtp_req->packets, item);
1970 }
1971
1972 return TAP_PACKET_REDRAW;
1973 }
1974
1975 /**
1976 * sharkd_session_process_tap_rtp_analyse_cb()
1977 *
1978 * Output rtp analyse tap:
1979 * (m) tap - tap name
1980 * (m) type - tap output type
1981 * (m) ssrc - RTP SSRC
1982 * (m) max_delta - Max delta (ms)
1983 * (m) max_delta_nr - Max delta packet #
1984 * (m) max_jitter - Max jitter (ms)
1985 * (m) mean_jitter - Mean jitter (ms)
1986 * (m) max_skew - Max skew (ms)
1987 * (m) total_nr - Total number of RTP packets
1988 * (m) seq_err - Number of sequence errors
1989 * (m) duration - Duration (ms)
1990 * (m) items - array of object with attributes:
1991 * (m) f - frame number
1992 * (m) o - arrive offset
1993 * (m) sn - sequence number
1994 * (m) d - delta
1995 * (m) j - jitter
1996 * (m) sk - skew
1997 * (m) bw - bandwidth
1998 * (o) s - status string
1999 * (o) t - status type
2000 * (o) mark - rtp mark
2001 */
2002 static void
sharkd_session_process_tap_rtp_analyse_cb(void * tapdata)2003 sharkd_session_process_tap_rtp_analyse_cb(void *tapdata)
2004 {
2005 const int RTP_TYPE_CN = 1;
2006 const int RTP_TYPE_ERROR = 2;
2007 const int RTP_TYPE_WARN = 3;
2008 const int RTP_TYPE_PT_EVENT = 4;
2009
2010 const struct sharkd_analyse_rtp *rtp_req = (struct sharkd_analyse_rtp *) tapdata;
2011 const tap_rtp_stat_t *statinfo = &rtp_req->statinfo;
2012
2013 GSList *l;
2014
2015 json_dumper_begin_object(&dumper);
2016
2017 sharkd_json_value_string("tap", rtp_req->tap_name);
2018 sharkd_json_value_string("type", "rtp-analyse");
2019 sharkd_json_value_anyf("ssrc", "%u", rtp_req->id.ssrc);
2020
2021 sharkd_json_value_anyf("max_delta", "%f", statinfo->max_delta);
2022 sharkd_json_value_anyf("max_delta_nr", "%u", statinfo->max_nr);
2023 sharkd_json_value_anyf("max_jitter", "%f", statinfo->max_jitter);
2024 sharkd_json_value_anyf("mean_jitter", "%f", statinfo->mean_jitter);
2025 sharkd_json_value_anyf("max_skew", "%f", statinfo->max_skew);
2026 sharkd_json_value_anyf("total_nr", "%u", statinfo->total_nr);
2027 sharkd_json_value_anyf("seq_err", "%u", statinfo->sequence);
2028 sharkd_json_value_anyf("duration", "%f", statinfo->time - statinfo->start_time);
2029
2030 sharkd_json_array_open("items");
2031 for (l = rtp_req->packets; l; l = l->next)
2032 {
2033 struct sharkd_analyse_rtp_items *item = (struct sharkd_analyse_rtp_items *) l->data;
2034
2035 json_dumper_begin_object(&dumper);
2036
2037 sharkd_json_value_anyf("f", "%u", item->frame_num);
2038 sharkd_json_value_anyf("o", "%.9f", item->arrive_offset);
2039 sharkd_json_value_anyf("sn", "%u", item->sequence_num);
2040 sharkd_json_value_anyf("d", "%.2f", item->delta);
2041 sharkd_json_value_anyf("j", "%.2f", item->jitter);
2042 sharkd_json_value_anyf("sk", "%.2f", item->skew);
2043 sharkd_json_value_anyf("bw", "%.2f", item->bandwidth);
2044
2045 if (item->pt == PT_CN)
2046 {
2047 sharkd_json_value_string("s", "Comfort noise (PT=13, RFC 3389)");
2048 sharkd_json_value_anyf("t", "%d", RTP_TYPE_CN);
2049 }
2050 else if (item->pt == PT_CN_OLD)
2051 {
2052 sharkd_json_value_string("s", "Comfort noise (PT=19, reserved)");
2053 sharkd_json_value_anyf("t", "%d", RTP_TYPE_CN);
2054 }
2055 else if (item->flags & STAT_FLAG_WRONG_SEQ)
2056 {
2057 sharkd_json_value_string("s", "Wrong sequence number");
2058 sharkd_json_value_anyf("t", "%d", RTP_TYPE_ERROR);
2059 }
2060 else if (item->flags & STAT_FLAG_DUP_PKT)
2061 {
2062 sharkd_json_value_string("s", "Suspected duplicate (MAC address) only delta time calculated");
2063 sharkd_json_value_anyf("t", "%d", RTP_TYPE_WARN);
2064 }
2065 else if (item->flags & STAT_FLAG_REG_PT_CHANGE)
2066 {
2067 sharkd_json_value_stringf("s", "Payload changed to PT=%u%s",
2068 item->pt,
2069 (item->flags & STAT_FLAG_PT_T_EVENT) ? " telephone/event" : "");
2070 sharkd_json_value_anyf("t", "%d", RTP_TYPE_WARN);
2071 }
2072 else if (item->flags & STAT_FLAG_WRONG_TIMESTAMP)
2073 {
2074 sharkd_json_value_string("s", "Incorrect timestamp");
2075 sharkd_json_value_anyf("t", "%d", RTP_TYPE_WARN);
2076 }
2077 else if ((item->flags & STAT_FLAG_PT_CHANGE)
2078 && !(item->flags & STAT_FLAG_FIRST)
2079 && !(item->flags & STAT_FLAG_PT_CN)
2080 && (item->flags & STAT_FLAG_FOLLOW_PT_CN)
2081 && !(item->flags & STAT_FLAG_MARKER))
2082 {
2083 sharkd_json_value_string("s", "Marker missing?");
2084 sharkd_json_value_anyf("t", "%d", RTP_TYPE_WARN);
2085 }
2086 else if (item->flags & STAT_FLAG_PT_T_EVENT)
2087 {
2088 sharkd_json_value_stringf("s", "PT=%u telephone/event", item->pt);
2089 sharkd_json_value_anyf("t", "%d", RTP_TYPE_PT_EVENT);
2090 }
2091 else if (item->flags & STAT_FLAG_MARKER)
2092 {
2093 sharkd_json_value_anyf("t", "%d", RTP_TYPE_WARN);
2094 }
2095
2096 if (item->marker)
2097 sharkd_json_value_anyf("mark", "1");
2098
2099 json_dumper_end_object(&dumper);
2100 }
2101 sharkd_json_array_close();
2102
2103 json_dumper_end_object(&dumper);
2104 }
2105
2106 /**
2107 * sharkd_session_process_tap_conv_cb()
2108 *
2109 * Output conv tap:
2110 * (m) tap - tap name
2111 * (m) type - tap output type
2112 * (m) proto - protocol short name
2113 * (o) filter - filter string
2114 * (o) geoip - whether GeoIP information is available, boolean
2115 *
2116 * (o) convs - array of object with attributes:
2117 * (m) saddr - source address
2118 * (m) daddr - destination address
2119 * (o) sport - source port
2120 * (o) dport - destination port
2121 * (m) txf - TX frame count
2122 * (m) txb - TX bytes
2123 * (m) rxf - RX frame count
2124 * (m) rxb - RX bytes
2125 * (m) start - (relative) first packet time
2126 * (m) stop - (relative) last packet time
2127 * (o) filter - conversation filter
2128 *
2129 * (o) hosts - array of object with attributes:
2130 * (m) host - host address
2131 * (o) port - host port
2132 * (m) txf - TX frame count
2133 * (m) txb - TX bytes
2134 * (m) rxf - RX frame count
2135 * (m) rxb - RX bytes
2136 */
2137 static void
sharkd_session_process_tap_conv_cb(void * arg)2138 sharkd_session_process_tap_conv_cb(void *arg)
2139 {
2140 conv_hash_t *hash = (conv_hash_t *) arg;
2141 const struct sharkd_conv_tap_data *iu = (struct sharkd_conv_tap_data *) hash->user_data;
2142 const char *proto;
2143 int proto_with_port;
2144 guint i;
2145
2146 int with_geoip = 0;
2147
2148 json_dumper_begin_object(&dumper);
2149 sharkd_json_value_string("tap", iu->type);
2150
2151 if (!strncmp(iu->type, "conv:", 5))
2152 {
2153 sharkd_json_value_string("type", "conv");
2154 sharkd_json_array_open("convs");
2155 proto = iu->type + 5;
2156 }
2157 else if (!strncmp(iu->type, "endpt:", 6))
2158 {
2159 sharkd_json_value_string("type", "host");
2160 sharkd_json_array_open("hosts");
2161 proto = iu->type + 6;
2162 }
2163 else
2164 {
2165 sharkd_json_value_string("type", "err");
2166 proto = "";
2167 }
2168
2169 proto_with_port = (!strcmp(proto, "TCP") || !strcmp(proto, "UDP") || !strcmp(proto, "SCTP"));
2170
2171 if (iu->hash.conv_array != NULL && !strncmp(iu->type, "conv:", 5))
2172 {
2173 for (i = 0; i < iu->hash.conv_array->len; i++)
2174 {
2175 conv_item_t *iui = &g_array_index(iu->hash.conv_array, conv_item_t, i);
2176 char *src_addr, *dst_addr;
2177 char *src_port, *dst_port;
2178 char *filter_str;
2179
2180 json_dumper_begin_object(&dumper);
2181
2182 sharkd_json_value_string("saddr", (src_addr = get_conversation_address(NULL, &iui->src_address, iu->resolve_name)));
2183 sharkd_json_value_string("daddr", (dst_addr = get_conversation_address(NULL, &iui->dst_address, iu->resolve_name)));
2184
2185 if (proto_with_port)
2186 {
2187 sharkd_json_value_string("sport", (src_port = get_conversation_port(NULL, iui->src_port, iui->etype, iu->resolve_port)));
2188 sharkd_json_value_string("dport", (dst_port = get_conversation_port(NULL, iui->dst_port, iui->etype, iu->resolve_port)));
2189
2190 wmem_free(NULL, src_port);
2191 wmem_free(NULL, dst_port);
2192 }
2193
2194 sharkd_json_value_anyf("rxf", "%" G_GUINT64_FORMAT, iui->rx_frames);
2195 sharkd_json_value_anyf("rxb", "%" G_GUINT64_FORMAT, iui->rx_bytes);
2196
2197 sharkd_json_value_anyf("txf", "%" G_GUINT64_FORMAT, iui->tx_frames);
2198 sharkd_json_value_anyf("txb", "%" G_GUINT64_FORMAT, iui->tx_bytes);
2199
2200 sharkd_json_value_anyf("start", "%.9f", nstime_to_sec(&iui->start_time));
2201 sharkd_json_value_anyf("stop", "%.9f", nstime_to_sec(&iui->stop_time));
2202
2203 filter_str = get_conversation_filter(iui, CONV_DIR_A_TO_FROM_B);
2204 if (filter_str)
2205 {
2206 sharkd_json_value_string("filter", filter_str);
2207 g_free(filter_str);
2208 }
2209
2210 wmem_free(NULL, src_addr);
2211 wmem_free(NULL, dst_addr);
2212
2213 if (sharkd_session_geoip_addr(&(iui->src_address), "1"))
2214 with_geoip = 1;
2215 if (sharkd_session_geoip_addr(&(iui->dst_address), "2"))
2216 with_geoip = 1;
2217
2218 json_dumper_end_object(&dumper);
2219 }
2220 }
2221 else if (iu->hash.conv_array != NULL && !strncmp(iu->type, "endpt:", 6))
2222 {
2223 for (i = 0; i < iu->hash.conv_array->len; i++)
2224 {
2225 hostlist_talker_t *host = &g_array_index(iu->hash.conv_array, hostlist_talker_t, i);
2226 char *host_str, *port_str;
2227 char *filter_str;
2228
2229 json_dumper_begin_object(&dumper);
2230
2231 sharkd_json_value_string("host", (host_str = get_conversation_address(NULL, &host->myaddress, iu->resolve_name)));
2232
2233 if (proto_with_port)
2234 {
2235 sharkd_json_value_string("port", (port_str = get_conversation_port(NULL, host->port, host->etype, iu->resolve_port)));
2236
2237 wmem_free(NULL, port_str);
2238 }
2239
2240 sharkd_json_value_anyf("rxf", "%" G_GUINT64_FORMAT, host->rx_frames);
2241 sharkd_json_value_anyf("rxb", "%" G_GUINT64_FORMAT, host->rx_bytes);
2242
2243 sharkd_json_value_anyf("txf", "%" G_GUINT64_FORMAT, host->tx_frames);
2244 sharkd_json_value_anyf("txb", "%" G_GUINT64_FORMAT, host->tx_bytes);
2245
2246 filter_str = get_hostlist_filter(host);
2247 if (filter_str)
2248 {
2249 sharkd_json_value_string("filter", filter_str);
2250 g_free(filter_str);
2251 }
2252
2253 wmem_free(NULL, host_str);
2254
2255 if (sharkd_session_geoip_addr(&(host->myaddress), ""))
2256 with_geoip = 1;
2257 json_dumper_end_object(&dumper);
2258 }
2259 }
2260 sharkd_json_array_close();
2261
2262 sharkd_json_value_string("proto", proto);
2263 sharkd_json_value_anyf("geoip", with_geoip ? "true" : "false");
2264
2265 json_dumper_end_object(&dumper);
2266 }
2267
2268 static void
sharkd_session_free_tap_conv_cb(void * arg)2269 sharkd_session_free_tap_conv_cb(void *arg)
2270 {
2271 conv_hash_t *hash = (conv_hash_t *) arg;
2272 struct sharkd_conv_tap_data *iu = (struct sharkd_conv_tap_data *) hash->user_data;
2273
2274 if (!strncmp(iu->type, "conv:", 5))
2275 {
2276 reset_conversation_table_data(hash);
2277 }
2278 else if (!strncmp(iu->type, "endpt:", 6))
2279 {
2280 reset_hostlist_table_data(hash);
2281 }
2282
2283 g_free(iu);
2284 }
2285
2286 /**
2287 * sharkd_session_process_tap_nstat_cb()
2288 *
2289 * Output nstat tap:
2290 * (m) tap - tap name
2291 * (m) type - tap output type
2292 * (m) fields: array of objects with attributes:
2293 * (m) c - name
2294 *
2295 * (m) tables: array of object with attributes:
2296 * (m) t - table title
2297 * (m) i - array of items
2298 */
2299 static void
sharkd_session_process_tap_nstat_cb(void * arg)2300 sharkd_session_process_tap_nstat_cb(void *arg)
2301 {
2302 stat_data_t *stat_data = (stat_data_t *) arg;
2303 guint i, j, k;
2304
2305 json_dumper_begin_object(&dumper);
2306 sharkd_json_value_stringf("tap", "nstat:%s", stat_data->stat_tap_data->cli_string);
2307 sharkd_json_value_string("type", "nstat");
2308
2309 sharkd_json_array_open("fields");
2310 for (i = 0; i < stat_data->stat_tap_data->nfields; i++)
2311 {
2312 stat_tap_table_item *field = &(stat_data->stat_tap_data->fields[i]);
2313
2314 json_dumper_begin_object(&dumper);
2315 sharkd_json_value_string("c", field->column_name);
2316 json_dumper_end_object(&dumper);
2317 }
2318 sharkd_json_array_close();
2319
2320 sharkd_json_array_open("tables");
2321 for (i = 0; i < stat_data->stat_tap_data->tables->len; i++)
2322 {
2323 stat_tap_table *table = g_array_index(stat_data->stat_tap_data->tables, stat_tap_table *, i);
2324
2325 json_dumper_begin_object(&dumper);
2326
2327 sharkd_json_value_string("t", table->title);
2328
2329 sharkd_json_array_open("i");
2330 for (j = 0; j < table->num_elements; j++)
2331 {
2332 stat_tap_table_item_type *field_data;
2333
2334 field_data = stat_tap_get_field_data(table, j, 0);
2335 if (field_data == NULL || field_data->type == TABLE_ITEM_NONE) /* Nothing for us here */
2336 continue;
2337
2338 sharkd_json_array_open(NULL);
2339 for (k = 0; k < table->num_fields; k++)
2340 {
2341 field_data = stat_tap_get_field_data(table, j, k);
2342
2343 switch (field_data->type)
2344 {
2345 case TABLE_ITEM_UINT:
2346 sharkd_json_value_anyf(NULL, "%u", field_data->value.uint_value);
2347 break;
2348
2349 case TABLE_ITEM_INT:
2350 sharkd_json_value_anyf(NULL, "%d", field_data->value.int_value);
2351 break;
2352
2353 case TABLE_ITEM_STRING:
2354 sharkd_json_value_string(NULL, field_data->value.string_value);
2355 break;
2356
2357 case TABLE_ITEM_FLOAT:
2358 sharkd_json_value_anyf(NULL, "%f", field_data->value.float_value);
2359 break;
2360
2361 case TABLE_ITEM_ENUM:
2362 sharkd_json_value_anyf(NULL, "%d", field_data->value.enum_value);
2363 break;
2364
2365 case TABLE_ITEM_NONE:
2366 sharkd_json_value_anyf(NULL, "null");
2367 break;
2368 }
2369 }
2370
2371 sharkd_json_array_close();
2372 }
2373 sharkd_json_array_close();
2374 json_dumper_end_object(&dumper);
2375 }
2376 sharkd_json_array_close();
2377
2378 json_dumper_end_object(&dumper);
2379 }
2380
2381 static void
sharkd_session_free_tap_nstat_cb(void * arg)2382 sharkd_session_free_tap_nstat_cb(void *arg)
2383 {
2384 stat_data_t *stat_data = (stat_data_t *) arg;
2385
2386 free_stat_tables(stat_data->stat_tap_data);
2387 }
2388
2389 /**
2390 * sharkd_session_process_tap_rtd_cb()
2391 *
2392 * Output rtd tap:
2393 * (m) tap - tap name
2394 * (m) type - tap output type
2395 * (m) stats - statistics rows - array object with attributes:
2396 * (m) type - statistic name
2397 * (m) num - number of messages
2398 * (m) min - minimum SRT time
2399 * (m) max - maximum SRT time
2400 * (m) tot - total SRT time
2401 * (m) min_frame - minimal SRT
2402 * (m) max_frame - maximum SRT
2403 * (o) open_req - Open Requests
2404 * (o) disc_rsp - Discarded Responses
2405 * (o) req_dup - Duplicated Requests
2406 * (o) rsp_dup - Duplicated Responses
2407 * (o) open_req - Open Requests
2408 * (o) disc_rsp - Discarded Responses
2409 * (o) req_dup - Duplicated Requests
2410 * (o) rsp_dup - Duplicated Responses
2411 */
2412 static void
sharkd_session_process_tap_rtd_cb(void * arg)2413 sharkd_session_process_tap_rtd_cb(void *arg)
2414 {
2415 rtd_data_t *rtd_data = (rtd_data_t *) arg;
2416 register_rtd_t *rtd = (register_rtd_t *) rtd_data->user_data;
2417
2418 guint i, j;
2419
2420 const char *filter = proto_get_protocol_filter_name(get_rtd_proto_id(rtd));
2421
2422 /* XXX, some dissectors are having single table and multiple timestats (mgcp, megaco),
2423 * some multiple table and single timestat (radius, h225)
2424 * and it seems that value_string is used one for timestamp-ID, other one for table-ID
2425 * I wonder how it will gonna work with multiple timestats and multiple tables...
2426 * (for usage grep for: register_rtd_table)
2427 */
2428 const value_string *vs = get_rtd_value_string(rtd);
2429
2430 json_dumper_begin_object(&dumper);
2431 sharkd_json_value_stringf("tap", "rtd:%s", filter);
2432 sharkd_json_value_string("type", "rtd");
2433
2434 if (rtd_data->stat_table.num_rtds == 1)
2435 {
2436 const rtd_timestat *ms = &rtd_data->stat_table.time_stats[0];
2437
2438 sharkd_json_value_anyf("open_req", "%u", ms->open_req_num);
2439 sharkd_json_value_anyf("disc_rsp", "%u", ms->disc_rsp_num);
2440 sharkd_json_value_anyf("req_dup", "%u", ms->req_dup_num);
2441 sharkd_json_value_anyf("rsp_dup", "%u", ms->rsp_dup_num);
2442 }
2443
2444 sharkd_json_array_open("stats");
2445 for (i = 0; i < rtd_data->stat_table.num_rtds; i++)
2446 {
2447 const rtd_timestat *ms = &rtd_data->stat_table.time_stats[i];
2448
2449 for (j = 0; j < ms->num_timestat; j++)
2450 {
2451 const char *type_str;
2452
2453 if (ms->rtd[j].num == 0)
2454 continue;
2455
2456 json_dumper_begin_object(&dumper);
2457
2458 if (rtd_data->stat_table.num_rtds == 1)
2459 type_str = val_to_str_const(j, vs, "Other"); /* 1 table - description per row */
2460 else
2461 type_str = val_to_str_const(i, vs, "Other"); /* multiple table - description per table */
2462 sharkd_json_value_string("type", type_str);
2463
2464 sharkd_json_value_anyf("num", "%u", ms->rtd[j].num);
2465 sharkd_json_value_anyf("min", "%.9f", nstime_to_sec(&(ms->rtd[j].min)));
2466 sharkd_json_value_anyf("max", "%.9f", nstime_to_sec(&(ms->rtd[j].max)));
2467 sharkd_json_value_anyf("tot", "%.9f", nstime_to_sec(&(ms->rtd[j].tot)));
2468 sharkd_json_value_anyf("min_frame", "%u", ms->rtd[j].min_num);
2469 sharkd_json_value_anyf("max_frame", "%u", ms->rtd[j].max_num);
2470
2471 if (rtd_data->stat_table.num_rtds != 1)
2472 {
2473 /* like in tshark, display it on every row */
2474 sharkd_json_value_anyf("open_req", "%u", ms->open_req_num);
2475 sharkd_json_value_anyf("disc_rsp", "%u", ms->disc_rsp_num);
2476 sharkd_json_value_anyf("req_dup", "%u", ms->req_dup_num);
2477 sharkd_json_value_anyf("rsp_dup", "%u", ms->rsp_dup_num);
2478 }
2479
2480 json_dumper_end_object(&dumper);
2481 }
2482 }
2483 sharkd_json_array_close();
2484
2485 json_dumper_end_object(&dumper);
2486 }
2487
2488 static void
sharkd_session_free_tap_rtd_cb(void * arg)2489 sharkd_session_free_tap_rtd_cb(void *arg)
2490 {
2491 rtd_data_t *rtd_data = (rtd_data_t *) arg;
2492
2493 free_rtd_table(&rtd_data->stat_table);
2494 g_free(rtd_data);
2495 }
2496
2497 /**
2498 * sharkd_session_process_tap_srt_cb()
2499 *
2500 * Output srt tap:
2501 * (m) tap - tap name
2502 * (m) type - tap output type
2503 *
2504 * (m) tables - array of object with attributes:
2505 * (m) n - table name
2506 * (m) f - table filter
2507 * (o) c - table column name
2508 * (m) r - table rows - array object with attributes:
2509 * (m) n - row name
2510 * (m) idx - procedure index
2511 * (m) num - number of events
2512 * (m) min - minimum SRT time
2513 * (m) max - maximum SRT time
2514 * (m) tot - total SRT time
2515 */
2516 static void
sharkd_session_process_tap_srt_cb(void * arg)2517 sharkd_session_process_tap_srt_cb(void *arg)
2518 {
2519 srt_data_t *srt_data = (srt_data_t *) arg;
2520 register_srt_t *srt = (register_srt_t *) srt_data->user_data;
2521
2522 const char *filter = proto_get_protocol_filter_name(get_srt_proto_id(srt));
2523
2524 guint i;
2525
2526 json_dumper_begin_object(&dumper);
2527 sharkd_json_value_stringf("tap", "srt:%s", filter);
2528 sharkd_json_value_string("type", "srt");
2529
2530 sharkd_json_array_open("tables");
2531 for (i = 0; i < srt_data->srt_array->len; i++)
2532 {
2533 /* SRT table */
2534 srt_stat_table *rst = g_array_index(srt_data->srt_array, srt_stat_table *, i);
2535
2536 int j;
2537
2538 json_dumper_begin_object(&dumper);
2539
2540 if (rst->name)
2541 sharkd_json_value_string("n", rst->name);
2542 else if (rst->short_name)
2543 sharkd_json_value_string("n", rst->short_name);
2544 else
2545 sharkd_json_value_stringf("n", "table%u", i);
2546
2547 if (rst->filter_string)
2548 sharkd_json_value_string("f", rst->filter_string);
2549
2550 if (rst->proc_column_name)
2551 sharkd_json_value_string("c", rst->proc_column_name);
2552
2553 sharkd_json_array_open("r");
2554 for (j = 0; j < rst->num_procs; j++)
2555 {
2556 /* SRT row */
2557 srt_procedure_t *proc = &rst->procedures[j];
2558
2559 if (proc->stats.num == 0)
2560 continue;
2561
2562 json_dumper_begin_object(&dumper);
2563
2564 sharkd_json_value_string("n", proc->procedure);
2565
2566 if (rst->filter_string)
2567 sharkd_json_value_anyf("idx", "%d", proc->proc_index);
2568
2569 sharkd_json_value_anyf("num", "%u", proc->stats.num);
2570
2571 sharkd_json_value_anyf("min", "%.9f", nstime_to_sec(&proc->stats.min));
2572 sharkd_json_value_anyf("max", "%.9f", nstime_to_sec(&proc->stats.max));
2573 sharkd_json_value_anyf("tot", "%.9f", nstime_to_sec(&proc->stats.tot));
2574
2575 json_dumper_end_object(&dumper);
2576 }
2577 sharkd_json_array_close();
2578
2579 json_dumper_end_object(&dumper);
2580 }
2581 sharkd_json_array_close();
2582
2583 json_dumper_end_object(&dumper);
2584 }
2585
2586 static void
sharkd_session_free_tap_srt_cb(void * arg)2587 sharkd_session_free_tap_srt_cb(void *arg)
2588 {
2589 srt_data_t *srt_data = (srt_data_t *) arg;
2590 register_srt_t *srt = (register_srt_t *) srt_data->user_data;
2591
2592 free_srt_table(srt, srt_data->srt_array);
2593 g_array_free(srt_data->srt_array, TRUE);
2594 g_free(srt_data);
2595 }
2596
2597 struct sharkd_export_object_list
2598 {
2599 struct sharkd_export_object_list *next;
2600
2601 char *type;
2602 const char *proto;
2603 GSList *entries;
2604 };
2605
2606 static struct sharkd_export_object_list *sharkd_eo_list;
2607
2608 /**
2609 * sharkd_session_process_tap_eo_cb()
2610 *
2611 * Output eo tap:
2612 * (m) tap - tap name
2613 * (m) type - tap output type
2614 * (m) proto - protocol short name
2615 * (m) objects - array of object with attributes:
2616 * (m) pkt - packet number
2617 * (o) hostname - hostname
2618 * (o) type - content type
2619 * (o) filename - filename
2620 * (m) len - object length
2621 */
2622 static void
sharkd_session_process_tap_eo_cb(void * tapdata)2623 sharkd_session_process_tap_eo_cb(void *tapdata)
2624 {
2625 export_object_list_t *tap_object = (export_object_list_t *) tapdata;
2626 struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) tap_object->gui_data;
2627 GSList *slist;
2628 int i = 0;
2629
2630 json_dumper_begin_object(&dumper);
2631 sharkd_json_value_string("tap", object_list->type);
2632 sharkd_json_value_string("type", "eo");
2633
2634 sharkd_json_value_string("proto", object_list->proto);
2635
2636 sharkd_json_array_open("objects");
2637 for (slist = object_list->entries; slist; slist = slist->next)
2638 {
2639 const export_object_entry_t *eo_entry = (export_object_entry_t *) slist->data;
2640
2641 json_dumper_begin_object(&dumper);
2642
2643 sharkd_json_value_anyf("pkt", "%u", eo_entry->pkt_num);
2644
2645 if (eo_entry->hostname)
2646 sharkd_json_value_string("hostname", eo_entry->hostname);
2647
2648 if (eo_entry->content_type)
2649 sharkd_json_value_string("type", eo_entry->content_type);
2650
2651 if (eo_entry->filename)
2652 sharkd_json_value_string("filename", eo_entry->filename);
2653
2654 sharkd_json_value_stringf("_download", "%s_%d", object_list->type, i);
2655
2656 sharkd_json_value_anyf("len", "%zu", eo_entry->payload_len);
2657
2658 json_dumper_end_object(&dumper);
2659
2660 i++;
2661 }
2662 sharkd_json_array_close();
2663
2664 json_dumper_end_object(&dumper);
2665 }
2666
2667 static void
sharkd_eo_object_list_add_entry(void * gui_data,export_object_entry_t * entry)2668 sharkd_eo_object_list_add_entry(void *gui_data, export_object_entry_t *entry)
2669 {
2670 struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) gui_data;
2671
2672 object_list->entries = g_slist_append(object_list->entries, entry);
2673 }
2674
2675 static export_object_entry_t *
sharkd_eo_object_list_get_entry(void * gui_data,int row)2676 sharkd_eo_object_list_get_entry(void *gui_data, int row)
2677 {
2678 struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) gui_data;
2679
2680 return (export_object_entry_t *) g_slist_nth_data(object_list->entries, row);
2681 }
2682
2683 /**
2684 * sharkd_session_process_tap_rtp_cb()
2685 *
2686 * Output RTP streams tap:
2687 * (m) tap - tap name
2688 * (m) type - tap output type
2689 * (m) streams - array of object with attributes:
2690 * (m) ssrc - RTP synchronization source identifier
2691 * (m) payload - stream payload
2692 * (m) saddr - source address
2693 * (m) sport - source port
2694 * (m) daddr - destination address
2695 * (m) dport - destination port
2696 * (m) pkts - packets count
2697 * (m) max_delta - max delta (ms)
2698 * (m) max_jitter - max jitter (ms)
2699 * (m) mean_jitter - mean jitter (ms)
2700 * (m) expectednr -
2701 * (m) totalnr -
2702 * (m) problem - if analyser found the problem
2703 * (m) ipver - address IP version (4 or 6)
2704 */
2705 static void
sharkd_session_process_tap_rtp_cb(void * arg)2706 sharkd_session_process_tap_rtp_cb(void *arg)
2707 {
2708 rtpstream_tapinfo_t *rtp_tapinfo = (rtpstream_tapinfo_t *) arg;
2709
2710 GList *listx;
2711
2712 json_dumper_begin_object(&dumper);
2713 sharkd_json_value_string("tap", "rtp-streams");
2714 sharkd_json_value_string("type", "rtp-streams");
2715
2716 sharkd_json_array_open("streams");
2717 for (listx = g_list_first(rtp_tapinfo->strinfo_list); listx; listx = listx->next)
2718 {
2719 rtpstream_info_t *streaminfo = (rtpstream_info_t *) listx->data;
2720 rtpstream_info_calc_t calc;
2721
2722 rtpstream_info_calculate(streaminfo, &calc);
2723
2724 json_dumper_begin_object(&dumper);
2725
2726 sharkd_json_value_anyf("ssrc", "%u", calc.ssrc);
2727 sharkd_json_value_string("payload", calc.all_payload_type_names);
2728
2729 sharkd_json_value_string("saddr", calc.src_addr_str);
2730 sharkd_json_value_anyf("sport", "%u", calc.src_port);
2731 sharkd_json_value_string("daddr", calc.dst_addr_str);
2732 sharkd_json_value_anyf("dport", "%u", calc.dst_port);
2733
2734 sharkd_json_value_anyf("pkts", "%u", calc.packet_count);
2735
2736 sharkd_json_value_anyf("max_delta", "%f",calc.max_delta);
2737 sharkd_json_value_anyf("max_jitter", "%f", calc.max_jitter);
2738 sharkd_json_value_anyf("mean_jitter", "%f", calc.mean_jitter);
2739
2740 sharkd_json_value_anyf("expectednr", "%u", calc.packet_expected);
2741 sharkd_json_value_anyf("totalnr", "%u", calc.total_nr);
2742
2743 sharkd_json_value_anyf("problem", calc.problem ? "true" : "false");
2744
2745 /* for filter */
2746 sharkd_json_value_anyf("ipver", "%d", (streaminfo->id.src_addr.type == AT_IPv6) ? 6 : 4);
2747
2748 rtpstream_info_calc_free(&calc);
2749
2750 json_dumper_end_object(&dumper);
2751 }
2752 sharkd_json_array_close();
2753
2754 json_dumper_end_object(&dumper);
2755 }
2756
2757 /**
2758 * sharkd_session_process_tap()
2759 *
2760 * Process tap request
2761 *
2762 * Input:
2763 * (m) tap0 - First tap request
2764 * (o) tap1...tap15 - Other tap requests
2765 *
2766 * Output object with attributes:
2767 * (m) taps - array of object with attributes:
2768 * (m) tap - tap name
2769 * (m) type - tap output type
2770 * ...
2771 * for type:stats see sharkd_session_process_tap_stats_cb()
2772 * for type:nstat see sharkd_session_process_tap_nstat_cb()
2773 * for type:conv see sharkd_session_process_tap_conv_cb()
2774 * for type:host see sharkd_session_process_tap_conv_cb()
2775 * for type:rtp-streams see sharkd_session_process_tap_rtp_cb()
2776 * for type:rtp-analyse see sharkd_session_process_tap_rtp_analyse_cb()
2777 * for type:eo see sharkd_session_process_tap_eo_cb()
2778 * for type:expert see sharkd_session_process_tap_expert_cb()
2779 * for type:rtd see sharkd_session_process_tap_rtd_cb()
2780 * for type:srt see sharkd_session_process_tap_srt_cb()
2781 * for type:flow see sharkd_session_process_tap_flow_cb()
2782 *
2783 * (m) err - error code
2784 */
2785 static void
sharkd_session_process_tap(char * buf,const jsmntok_t * tokens,int count)2786 sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count)
2787 {
2788 void *taps_data[16];
2789 GFreeFunc taps_free[16];
2790 int taps_count = 0;
2791 int i;
2792
2793 rtpstream_tapinfo_t rtp_tapinfo =
2794 { NULL, NULL, NULL, NULL, 0, NULL, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, FALSE, FALSE};
2795
2796 for (i = 0; i < 16; i++)
2797 {
2798 char tapbuf[32];
2799 const char *tok_tap;
2800
2801 void *tap_data = NULL;
2802 GFreeFunc tap_free = NULL;
2803 const char *tap_filter = "";
2804 GString *tap_error = NULL;
2805
2806 snprintf(tapbuf, sizeof(tapbuf), "tap%d", i);
2807 tok_tap = json_find_attr(buf, tokens, count, tapbuf);
2808 if (!tok_tap)
2809 break;
2810
2811 if (!strncmp(tok_tap, "stat:", 5))
2812 {
2813 stats_tree_cfg *cfg = stats_tree_get_cfg_by_abbr(tok_tap + 5);
2814 stats_tree *st;
2815
2816 if (!cfg)
2817 {
2818 sharkd_json_error(
2819 rpcid, -11001, NULL,
2820 "sharkd_session_process_tap() stat %s not found", tok_tap + 5
2821 );
2822 return;
2823 }
2824
2825 st = stats_tree_new(cfg, NULL, tap_filter);
2826
2827 tap_error = register_tap_listener(st->cfg->tapname, st, st->filter, st->cfg->flags, stats_tree_reset, stats_tree_packet, sharkd_session_process_tap_stats_cb, NULL);
2828
2829 if (!tap_error && cfg->init)
2830 cfg->init(st);
2831
2832 tap_data = st;
2833 tap_free = sharkd_session_free_tap_stats_cb;
2834 }
2835 else if (!strcmp(tok_tap, "expert"))
2836 {
2837 struct sharkd_expert_tap *expert_tap;
2838
2839 expert_tap = g_new0(struct sharkd_expert_tap, 1);
2840 expert_tap->text = g_string_chunk_new(100);
2841
2842 tap_error = register_tap_listener("expert", expert_tap, NULL, 0, NULL, sharkd_session_packet_tap_expert_cb, sharkd_session_process_tap_expert_cb, NULL);
2843
2844 tap_data = expert_tap;
2845 tap_free = sharkd_session_free_tap_expert_cb;
2846 }
2847 else if (!strncmp(tok_tap, "seqa:", 5))
2848 {
2849 seq_analysis_info_t *graph_analysis;
2850 register_analysis_t *analysis;
2851 const char *tap_name;
2852 tap_packet_cb tap_func;
2853 guint tap_flags;
2854
2855 analysis = sequence_analysis_find_by_name(tok_tap + 5);
2856 if (!analysis)
2857 {
2858 sharkd_json_error(
2859 rpcid, -11002, NULL,
2860 "sharkd_session_process_tap() seq analysis %s not found", tok_tap + 5
2861 );
2862 return;
2863 }
2864
2865 graph_analysis = sequence_analysis_info_new();
2866 graph_analysis->name = tok_tap + 5;
2867 /* TODO, make configurable */
2868 graph_analysis->any_addr = FALSE;
2869
2870 tap_name = sequence_analysis_get_tap_listener_name(analysis);
2871 tap_flags = sequence_analysis_get_tap_flags(analysis);
2872 tap_func = sequence_analysis_get_packet_func(analysis);
2873
2874 tap_error = register_tap_listener(tap_name, graph_analysis, NULL, tap_flags, NULL, tap_func, sharkd_session_process_tap_flow_cb, NULL);
2875
2876 tap_data = graph_analysis;
2877 tap_free = sharkd_session_free_tap_flow_cb;
2878 }
2879 else if (!strncmp(tok_tap, "conv:", 5) || !strncmp(tok_tap, "endpt:", 6))
2880 {
2881 struct register_ct *ct = NULL;
2882 const char *ct_tapname;
2883 struct sharkd_conv_tap_data *ct_data;
2884 tap_packet_cb tap_func = NULL;
2885
2886 if (!strncmp(tok_tap, "conv:", 5))
2887 {
2888 ct = get_conversation_by_proto_id(proto_get_id_by_short_name(tok_tap + 5));
2889
2890 if (!ct || !(tap_func = get_conversation_packet_func(ct)))
2891 {
2892 sharkd_json_error(
2893 rpcid, -11003, NULL,
2894 "sharkd_session_process_tap() conv %s not found", tok_tap + 5
2895 );
2896 return;
2897 }
2898 }
2899 else if (!strncmp(tok_tap, "endpt:", 6))
2900 {
2901 ct = get_conversation_by_proto_id(proto_get_id_by_short_name(tok_tap + 6));
2902
2903 if (!ct || !(tap_func = get_hostlist_packet_func(ct)))
2904 {
2905 sharkd_json_error(
2906 rpcid, -11004, NULL,
2907 "sharkd_session_process_tap() endpt %s not found", tok_tap + 6
2908 );
2909 return;
2910 }
2911 }
2912 else
2913 {
2914 sharkd_json_error(
2915 rpcid, -11005, NULL,
2916 "sharkd_session_process_tap() conv/endpt(?): %s not found", tok_tap
2917 );
2918 return;
2919 }
2920
2921 ct_tapname = proto_get_protocol_filter_name(get_conversation_proto_id(ct));
2922
2923 ct_data = g_new0(struct sharkd_conv_tap_data, 1);
2924 ct_data->type = tok_tap;
2925 ct_data->hash.user_data = ct_data;
2926
2927 /* XXX: make configurable */
2928 ct_data->resolve_name = TRUE;
2929 ct_data->resolve_port = TRUE;
2930
2931 tap_error = register_tap_listener(ct_tapname, &ct_data->hash, tap_filter, 0, NULL, tap_func, sharkd_session_process_tap_conv_cb, NULL);
2932
2933 tap_data = &ct_data->hash;
2934 tap_free = sharkd_session_free_tap_conv_cb;
2935 }
2936 else if (!strncmp(tok_tap, "nstat:", 6))
2937 {
2938 stat_tap_table_ui *stat_tap = stat_tap_by_name(tok_tap + 6);
2939 stat_data_t *stat_data;
2940
2941 if (!stat_tap)
2942 {
2943 sharkd_json_error(
2944 rpcid, -11006, NULL,
2945 "sharkd_session_process_tap() nstat=%s not found", tok_tap + 6
2946 );
2947 return;
2948 }
2949
2950 stat_tap->stat_tap_init_cb(stat_tap);
2951
2952 stat_data = g_new0(stat_data_t, 1);
2953 stat_data->stat_tap_data = stat_tap;
2954 stat_data->user_data = NULL;
2955
2956 tap_error = register_tap_listener(stat_tap->tap_name, stat_data, tap_filter, 0, NULL, stat_tap->packet_func, sharkd_session_process_tap_nstat_cb, NULL);
2957
2958 tap_data = stat_data;
2959 tap_free = sharkd_session_free_tap_nstat_cb;
2960 }
2961 else if (!strncmp(tok_tap, "rtd:", 4))
2962 {
2963 register_rtd_t *rtd = get_rtd_table_by_name(tok_tap + 4);
2964 rtd_data_t *rtd_data;
2965 char *err;
2966
2967 if (!rtd)
2968 {
2969 sharkd_json_error(
2970 rpcid, -11007, NULL,
2971 "sharkd_session_process_tap() rtd=%s not found", tok_tap + 4
2972 );
2973 return;
2974 }
2975
2976 rtd_table_get_filter(rtd, "", &tap_filter, &err);
2977 if (err != NULL)
2978 {
2979 sharkd_json_error(
2980 rpcid, -11008, NULL,
2981 "sharkd_session_process_tap() rtd=%s err=%s", tok_tap + 4, err
2982 );
2983 g_free(err);
2984 return;
2985 }
2986
2987 rtd_data = g_new0(rtd_data_t, 1);
2988 rtd_data->user_data = rtd;
2989 rtd_table_dissector_init(rtd, &rtd_data->stat_table, NULL, NULL);
2990
2991 tap_error = register_tap_listener(get_rtd_tap_listener_name(rtd), rtd_data, tap_filter, 0, NULL, get_rtd_packet_func(rtd), sharkd_session_process_tap_rtd_cb, NULL);
2992
2993 tap_data = rtd_data;
2994 tap_free = sharkd_session_free_tap_rtd_cb;
2995 }
2996 else if (!strncmp(tok_tap, "srt:", 4))
2997 {
2998 register_srt_t *srt = get_srt_table_by_name(tok_tap + 4);
2999 srt_data_t *srt_data;
3000 char *err;
3001
3002 if (!srt)
3003 {
3004 sharkd_json_error(
3005 rpcid, -11009, NULL,
3006 "sharkd_session_process_tap() srt=%s not found", tok_tap + 4
3007 );
3008 return;
3009 }
3010
3011 srt_table_get_filter(srt, "", &tap_filter, &err);
3012 if (err != NULL)
3013 {
3014 sharkd_json_error(
3015 rpcid, -11010, NULL,
3016 "sharkd_session_process_tap() srt=%s err=%s", tok_tap + 4, err
3017 );
3018 g_free(err);
3019 return;
3020 }
3021
3022 srt_data = g_new0(srt_data_t, 1);
3023 srt_data->srt_array = g_array_new(FALSE, TRUE, sizeof(srt_stat_table *));
3024 srt_data->user_data = srt;
3025 srt_table_dissector_init(srt, srt_data->srt_array);
3026
3027 tap_error = register_tap_listener(get_srt_tap_listener_name(srt), srt_data, tap_filter, 0, NULL, get_srt_packet_func(srt), sharkd_session_process_tap_srt_cb, NULL);
3028
3029 tap_data = srt_data;
3030 tap_free = sharkd_session_free_tap_srt_cb;
3031 }
3032 else if (!strncmp(tok_tap, "eo:", 3))
3033 {
3034 register_eo_t *eo = get_eo_by_name(tok_tap + 3);
3035 export_object_list_t *eo_object;
3036 struct sharkd_export_object_list *object_list;
3037
3038 if (!eo)
3039 {
3040 sharkd_json_error(
3041 rpcid, -11011, NULL,
3042 "sharkd_session_process_tap() eo=%s not found", tok_tap + 3
3043 );
3044 return;
3045 }
3046
3047 for (object_list = sharkd_eo_list; object_list; object_list = object_list->next)
3048 {
3049 if (!strcmp(object_list->type, tok_tap))
3050 {
3051 g_slist_free_full(object_list->entries, (GDestroyNotify) eo_free_entry);
3052 object_list->entries = NULL;
3053 break;
3054 }
3055 }
3056
3057 if (!object_list)
3058 {
3059 object_list = g_new(struct sharkd_export_object_list, 1);
3060 object_list->type = g_strdup(tok_tap);
3061 object_list->proto = proto_get_protocol_short_name(find_protocol_by_id(get_eo_proto_id(eo)));
3062 object_list->entries = NULL;
3063 object_list->next = sharkd_eo_list;
3064 sharkd_eo_list = object_list;
3065 }
3066
3067 eo_object = g_new0(export_object_list_t, 1);
3068 eo_object->add_entry = sharkd_eo_object_list_add_entry;
3069 eo_object->get_entry = sharkd_eo_object_list_get_entry;
3070 eo_object->gui_data = (void *) object_list;
3071
3072 tap_error = register_tap_listener(get_eo_tap_listener_name(eo), eo_object, NULL, 0, NULL, get_eo_packet_func(eo), sharkd_session_process_tap_eo_cb, NULL);
3073
3074 tap_data = eo_object;
3075 tap_free = g_free; /* need to free only eo_object, object_list need to be kept for potential download */
3076 }
3077 else if (!strcmp(tok_tap, "rtp-streams"))
3078 {
3079 tap_error = register_tap_listener("rtp", &rtp_tapinfo, tap_filter, 0, rtpstream_reset_cb, rtpstream_packet_cb, sharkd_session_process_tap_rtp_cb, NULL);
3080
3081 tap_data = &rtp_tapinfo;
3082 tap_free = rtpstream_reset_cb;
3083 }
3084 else if (!strncmp(tok_tap, "rtp-analyse:", 12))
3085 {
3086 struct sharkd_analyse_rtp *rtp_req;
3087
3088 rtp_req = (struct sharkd_analyse_rtp *) g_malloc0(sizeof(*rtp_req));
3089 if (!sharkd_rtp_match_init(&rtp_req->id, tok_tap + 12))
3090 {
3091 rtpstream_id_free(&rtp_req->id);
3092 g_free(rtp_req);
3093 continue;
3094 }
3095
3096 rtp_req->tap_name = tok_tap;
3097 rtp_req->statinfo.first_packet = TRUE;
3098 rtp_req->statinfo.reg_pt = PT_UNDEFINED;
3099
3100 tap_error = register_tap_listener("rtp", rtp_req, tap_filter, 0, NULL, sharkd_session_packet_tap_rtp_analyse_cb, sharkd_session_process_tap_rtp_analyse_cb, NULL);
3101
3102 tap_data = rtp_req;
3103 tap_free = sharkd_session_process_tap_rtp_free_cb;
3104 }
3105 else
3106 {
3107 sharkd_json_error(
3108 rpcid, -11012, NULL,
3109 "sharkd_session_process_tap() %s not recognized", tok_tap
3110 );
3111 return;
3112 }
3113
3114 if (tap_error)
3115 {
3116 sharkd_json_error(
3117 rpcid, -11013, NULL,
3118 "sharkd_session_process_tap() name=%s error=%s", tok_tap, tap_error->str
3119 );
3120 g_string_free(tap_error, TRUE);
3121 if (tap_free)
3122 tap_free(tap_data);
3123 return;
3124 }
3125
3126 taps_data[taps_count] = tap_data;
3127 taps_free[taps_count] = tap_free;
3128 taps_count++;
3129 }
3130
3131 fprintf(stderr, "sharkd_session_process_tap() count=%d\n", taps_count);
3132 if (taps_count == 0)
3133 {
3134 sharkd_json_result_prologue(rpcid);
3135 sharkd_json_array_open("taps");
3136 sharkd_json_array_close();
3137 sharkd_json_result_epilogue();
3138 return;
3139 }
3140
3141 sharkd_json_result_prologue(rpcid);
3142 sharkd_json_array_open("taps");
3143 sharkd_retap();
3144 sharkd_json_array_close();
3145 sharkd_json_result_epilogue();
3146
3147 for (i = 0; i < taps_count; i++)
3148 {
3149 if (taps_data[i])
3150 remove_tap_listener(taps_data[i]);
3151
3152 if (taps_free[i])
3153 taps_free[i](taps_data[i]);
3154 }
3155 }
3156
3157 /**
3158 * sharkd_session_process_follow()
3159 *
3160 * Process follow request
3161 *
3162 * Input:
3163 * (m) follow - follow protocol request (e.g. HTTP)
3164 * (m) filter - filter request (e.g. tcp.stream == 1)
3165 *
3166 * Output object with attributes:
3167 *
3168 * (m) err - error code
3169 * (m) shost - server host
3170 * (m) sport - server port
3171 * (m) sbytes - server send bytes count
3172 * (m) chost - client host
3173 * (m) cport - client port
3174 * (m) cbytes - client send bytes count
3175 * (o) payloads - array of object with attributes:
3176 * (o) s - set if server sent, else client
3177 * (m) n - packet number
3178 * (m) d - data base64 encoded
3179 */
3180 static void
sharkd_session_process_follow(char * buf,const jsmntok_t * tokens,int count)3181 sharkd_session_process_follow(char *buf, const jsmntok_t *tokens, int count)
3182 {
3183 const char *tok_follow = json_find_attr(buf, tokens, count, "follow");
3184 const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
3185
3186 register_follow_t *follower;
3187 GString *tap_error;
3188
3189 follow_info_t *follow_info;
3190 const char *host;
3191 char *port;
3192
3193 follower = get_follow_by_name(tok_follow);
3194 if (!follower)
3195 {
3196 sharkd_json_error(
3197 rpcid, -12001, NULL,
3198 "sharkd_session_process_follow() follower=%s not found", tok_follow
3199 );
3200 return;
3201 }
3202
3203 /* follow_reset_stream ? */
3204 follow_info = g_new0(follow_info_t, 1);
3205 /* gui_data, filter_out_filter not set, but not used by dissector */
3206
3207 tap_error = register_tap_listener(get_follow_tap_string(follower), follow_info, tok_filter, 0, NULL, get_follow_tap_handler(follower), NULL, NULL);
3208 if (tap_error)
3209 {
3210 sharkd_json_error(
3211 rpcid, -12002, NULL,
3212 "sharkd_session_process_follow() name=%s error=%s", tok_follow, tap_error->str
3213 );
3214 g_string_free(tap_error, TRUE);
3215 g_free(follow_info);
3216 return;
3217 }
3218
3219 sharkd_retap();
3220
3221 sharkd_json_result_prologue(rpcid);
3222
3223 /* Server information: hostname, port, bytes sent */
3224 host = address_to_name(&follow_info->server_ip);
3225 sharkd_json_value_string("shost", host);
3226
3227 port = get_follow_port_to_display(follower)(NULL, follow_info->server_port);
3228 sharkd_json_value_string("sport", port);
3229 wmem_free(NULL, port);
3230
3231 sharkd_json_value_anyf("sbytes", "%u", follow_info->bytes_written[0]);
3232
3233 /* Client information: hostname, port, bytes sent */
3234 host = address_to_name(&follow_info->client_ip);
3235 sharkd_json_value_string("chost", host);
3236
3237 port = get_follow_port_to_display(follower)(NULL, follow_info->client_port);
3238 sharkd_json_value_string("cport", port);
3239 wmem_free(NULL, port);
3240
3241 sharkd_json_value_anyf("cbytes", "%u", follow_info->bytes_written[1]);
3242
3243 if (follow_info->payload)
3244 {
3245 follow_record_t *follow_record;
3246 GList *cur;
3247
3248 sharkd_json_array_open("payloads");
3249 for (cur = g_list_last(follow_info->payload); cur; cur = g_list_previous(cur))
3250 {
3251 follow_record = (follow_record_t *) cur->data;
3252
3253 json_dumper_begin_object(&dumper);
3254
3255 sharkd_json_value_anyf("n", "%u", follow_record->packet_num);
3256 sharkd_json_value_base64("d", follow_record->data->data, follow_record->data->len);
3257
3258 if (follow_record->is_server)
3259 sharkd_json_value_anyf("s", "%d", 1);
3260
3261 json_dumper_end_object(&dumper);
3262 }
3263 sharkd_json_array_close();
3264 }
3265
3266 sharkd_json_result_epilogue();
3267
3268 remove_tap_listener(follow_info);
3269 follow_info_free(follow_info);
3270 }
3271
3272 static void
sharkd_session_process_frame_cb_tree(epan_dissect_t * edt,proto_tree * tree,tvbuff_t ** tvbs,gboolean display_hidden)3273 sharkd_session_process_frame_cb_tree(epan_dissect_t *edt, proto_tree *tree, tvbuff_t **tvbs, gboolean display_hidden)
3274 {
3275 proto_node *node;
3276
3277 sharkd_json_array_open(NULL);
3278 for (node = tree->first_child; node; node = node->next)
3279 {
3280 field_info *finfo = PNODE_FINFO(node);
3281
3282 if (!finfo)
3283 continue;
3284
3285 if (!display_hidden && FI_GET_FLAG(finfo, FI_HIDDEN))
3286 continue;
3287
3288 json_dumper_begin_object(&dumper);
3289
3290 if (!finfo->rep)
3291 {
3292 char label_str[ITEM_LABEL_LENGTH];
3293
3294 label_str[0] = '\0';
3295 proto_item_fill_label(finfo, label_str);
3296 sharkd_json_value_string("l", label_str);
3297 }
3298 else
3299 {
3300 sharkd_json_value_string("l", finfo->rep->representation);
3301 }
3302
3303 if (finfo->ds_tvb && tvbs && tvbs[0] != finfo->ds_tvb)
3304 {
3305 int idx;
3306
3307 for (idx = 1; tvbs[idx]; idx++)
3308 {
3309 if (tvbs[idx] == finfo->ds_tvb)
3310 {
3311 sharkd_json_value_anyf("ds", "%d", idx);
3312 break;
3313 }
3314 }
3315 }
3316
3317 if (finfo->start >= 0 && finfo->length > 0)
3318 sharkd_json_value_anyf("h", "[%d,%d]", finfo->start, finfo->length);
3319
3320 if (finfo->appendix_start >= 0 && finfo->appendix_length > 0)
3321 sharkd_json_value_anyf("i", "[%d,%d]", finfo->appendix_start, finfo->appendix_length);
3322
3323
3324 if (finfo->hfinfo)
3325 {
3326 char *filter;
3327
3328 if (finfo->hfinfo->type == FT_PROTOCOL)
3329 {
3330 sharkd_json_value_string("t", "proto");
3331 }
3332 else if (finfo->hfinfo->type == FT_FRAMENUM)
3333 {
3334 sharkd_json_value_string("t", "framenum");
3335 sharkd_json_value_anyf("fnum", "%u", finfo->value.value.uinteger);
3336 }
3337 else if (FI_GET_FLAG(finfo, FI_URL) && IS_FT_STRING(finfo->hfinfo->type))
3338 {
3339 char *url = fvalue_to_string_repr(NULL, &finfo->value, FTREPR_DISPLAY, finfo->hfinfo->display);
3340
3341 sharkd_json_value_string("t", "url");
3342 sharkd_json_value_string("url", url);
3343 wmem_free(NULL, url);
3344 }
3345
3346 filter = proto_construct_match_selected_string(finfo, edt);
3347 if (filter)
3348 {
3349 sharkd_json_value_string("f", filter);
3350 wmem_free(NULL, filter);
3351 }
3352 }
3353
3354 if (FI_GET_FLAG(finfo, FI_GENERATED))
3355 sharkd_json_value_anyf("g", "true");
3356
3357 if (FI_GET_FLAG(finfo, FI_HIDDEN))
3358 sharkd_json_value_anyf("v", "true");
3359
3360 if (FI_GET_FLAG(finfo, PI_SEVERITY_MASK))
3361 {
3362 const char *severity = try_val_to_str(FI_GET_FLAG(finfo, PI_SEVERITY_MASK), expert_severity_vals);
3363
3364 ws_assert(severity != NULL);
3365
3366 sharkd_json_value_string("s", severity);
3367 }
3368
3369 if (((proto_tree *) node)->first_child)
3370 {
3371 if (finfo->tree_type != -1)
3372 sharkd_json_value_anyf("e", "%d", finfo->tree_type);
3373
3374 sharkd_json_value_anyf("n", NULL);
3375 sharkd_session_process_frame_cb_tree(edt, (proto_tree *) node, tvbs, display_hidden);
3376 }
3377
3378 json_dumper_end_object(&dumper);
3379 }
3380 sharkd_json_array_close();
3381 }
3382
3383 static gboolean
sharkd_follower_visit_layers_cb(const void * key _U_,void * value,void * user_data)3384 sharkd_follower_visit_layers_cb(const void *key _U_, void *value, void *user_data)
3385 {
3386 register_follow_t *follower = (register_follow_t *) value;
3387 packet_info *pi = (packet_info *) user_data;
3388
3389 const int proto_id = get_follow_proto_id(follower);
3390
3391 guint32 ignore_stream;
3392 guint32 ignore_sub_stream;
3393
3394 if (proto_is_frame_protocol(pi->layers, proto_get_protocol_filter_name(proto_id)))
3395 {
3396 const char *layer_proto = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
3397 char *follow_filter;
3398
3399 follow_filter = get_follow_conv_func(follower)(NULL, pi, &ignore_stream, &ignore_sub_stream);
3400
3401 json_dumper_begin_array(&dumper);
3402 json_dumper_value_string(&dumper, layer_proto);
3403 json_dumper_value_string(&dumper, follow_filter);
3404 json_dumper_end_array(&dumper);
3405
3406 g_free(follow_filter);
3407 }
3408
3409 return FALSE;
3410 }
3411
3412 struct sharkd_frame_request_data
3413 {
3414 gboolean display_hidden;
3415 };
3416
3417 static void
sharkd_session_process_frame_cb(epan_dissect_t * edt,proto_tree * tree,struct epan_column_info * cinfo,const GSList * data_src,void * data)3418 sharkd_session_process_frame_cb(epan_dissect_t *edt, proto_tree *tree, struct epan_column_info *cinfo, const GSList *data_src, void *data)
3419 {
3420 packet_info *pi = &edt->pi;
3421 frame_data *fdata = pi->fd;
3422 wtap_block_t pkt_block = NULL;
3423
3424 const struct sharkd_frame_request_data * const req_data = (const struct sharkd_frame_request_data * const) data;
3425 const gboolean display_hidden = (req_data) ? req_data->display_hidden : FALSE;
3426
3427 sharkd_json_result_prologue(rpcid);
3428
3429 if (fdata->has_modified_block)
3430 pkt_block = sharkd_get_modified_block(fdata);
3431 else
3432 pkt_block = pi->rec->block;
3433
3434 if (pkt_block)
3435 {
3436 guint i;
3437 guint n;
3438 gchar *comment;
3439
3440 n = wtap_block_count_option(pkt_block, OPT_COMMENT);
3441
3442 sharkd_json_array_open("comment");
3443 for (i = 0; i < n; i++) {
3444 if (WTAP_OPTTYPE_SUCCESS == wtap_block_get_nth_string_option_value(pkt_block, OPT_COMMENT, i, &comment)) {
3445 sharkd_json_value_string(NULL, comment);
3446 }
3447 }
3448 sharkd_json_array_close();
3449 }
3450
3451 if (tree)
3452 {
3453 tvbuff_t **tvbs = NULL;
3454
3455 /* arrayize data src, to speedup searching for ds_tvb index */
3456 if (data_src && data_src->next /* only needed if there are more than one data source */)
3457 {
3458 guint count = g_slist_length((GSList *) data_src);
3459 guint i;
3460
3461 tvbs = (tvbuff_t **) g_malloc0((count + 1) * sizeof(*tvbs));
3462
3463 for (i = 0; i < count; i++)
3464 {
3465 const struct data_source *src = (const struct data_source *) g_slist_nth_data((GSList *) data_src, i);
3466
3467 tvbs[i] = get_data_source_tvb(src);
3468 }
3469
3470 tvbs[count] = NULL;
3471 }
3472
3473 sharkd_json_value_anyf("tree", NULL);
3474 sharkd_session_process_frame_cb_tree(edt, tree, tvbs, display_hidden);
3475
3476 g_free(tvbs);
3477 }
3478
3479 if (cinfo)
3480 {
3481 int col;
3482
3483 sharkd_json_array_open("col");
3484 for (col = 0; col < cinfo->num_cols; ++col)
3485 {
3486 const col_item_t *col_item = &cinfo->columns[col];
3487
3488 sharkd_json_value_string(NULL, col_item->col_data);
3489 }
3490 sharkd_json_array_close();
3491 }
3492
3493 if (fdata->ignored)
3494 sharkd_json_value_anyf("i", "true");
3495
3496 if (fdata->marked)
3497 sharkd_json_value_anyf("m", "true");
3498
3499 if (fdata->color_filter)
3500 {
3501 sharkd_json_value_stringf("bg", "%x", color_t_to_rgb(&fdata->color_filter->bg_color));
3502 sharkd_json_value_stringf("fg", "%x", color_t_to_rgb(&fdata->color_filter->fg_color));
3503 }
3504
3505 if (data_src)
3506 {
3507 struct data_source *src = (struct data_source *) data_src->data;
3508 gboolean ds_open = FALSE;
3509
3510 tvbuff_t *tvb;
3511 guint length;
3512
3513 tvb = get_data_source_tvb(src);
3514 length = tvb_captured_length(tvb);
3515
3516 if (length != 0)
3517 {
3518 const guchar *cp = tvb_get_ptr(tvb, 0, length);
3519
3520 /* XXX pi.fd->encoding */
3521 sharkd_json_value_base64("bytes", cp, length);
3522 }
3523 else
3524 {
3525 sharkd_json_value_base64("bytes", "", 0);
3526 }
3527
3528 data_src = data_src->next;
3529 if (data_src)
3530 {
3531 sharkd_json_array_open("ds");
3532 ds_open = TRUE;
3533 }
3534
3535 while (data_src)
3536 {
3537 src = (struct data_source *) data_src->data;
3538
3539 json_dumper_begin_object(&dumper);
3540
3541 {
3542 char *src_name = get_data_source_name(src);
3543
3544 sharkd_json_value_string("name", src_name);
3545 wmem_free(NULL, src_name);
3546 }
3547
3548 tvb = get_data_source_tvb(src);
3549 length = tvb_captured_length(tvb);
3550
3551 if (length != 0)
3552 {
3553 const guchar *cp = tvb_get_ptr(tvb, 0, length);
3554
3555 /* XXX pi.fd->encoding */
3556 sharkd_json_value_base64("bytes", cp, length);
3557 }
3558 else
3559 {
3560 sharkd_json_value_base64("bytes", "", 0);
3561 }
3562
3563 json_dumper_end_object(&dumper);
3564
3565 data_src = data_src->next;
3566 }
3567
3568 /* close ds, only if was opened */
3569 if (ds_open)
3570 sharkd_json_array_close();
3571 }
3572
3573 sharkd_json_array_open("fol");
3574 follow_iterate_followers(sharkd_follower_visit_layers_cb, pi);
3575 sharkd_json_array_close();
3576
3577 sharkd_json_result_epilogue();
3578 }
3579
3580 #define SHARKD_IOGRAPH_MAX_ITEMS 250000 /* 250k limit of items is taken from wireshark-qt, on x86_64 sizeof(io_graph_item_t) is 152, so single graph can take max 36 MB */
3581
3582 struct sharkd_iograph
3583 {
3584 /* config */
3585 int hf_index;
3586 io_graph_item_unit_t calc_type;
3587 guint32 interval;
3588
3589 /* result */
3590 int space_items;
3591 int num_items;
3592 io_graph_item_t *items;
3593 GString *error;
3594 };
3595
3596 static tap_packet_status
sharkd_iograph_packet(void * g,packet_info * pinfo,epan_dissect_t * edt,const void * dummy _U_)3597 sharkd_iograph_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
3598 {
3599 struct sharkd_iograph *graph = (struct sharkd_iograph *) g;
3600 int idx;
3601 gboolean update_succeeded;
3602
3603 idx = get_io_graph_index(pinfo, graph->interval);
3604 if (idx < 0 || idx >= SHARKD_IOGRAPH_MAX_ITEMS)
3605 return TAP_PACKET_DONT_REDRAW;
3606
3607 if (idx + 1 > graph->num_items)
3608 {
3609 if (idx + 1 > graph->space_items)
3610 {
3611 int new_size = idx + 1024;
3612
3613 graph->items = (io_graph_item_t *) g_realloc(graph->items, sizeof(io_graph_item_t) * new_size);
3614 reset_io_graph_items(&graph->items[graph->space_items], new_size - graph->space_items);
3615
3616 graph->space_items = new_size;
3617 }
3618 else if (graph->items == NULL)
3619 {
3620 graph->items = g_new(io_graph_item_t, graph->space_items);
3621 reset_io_graph_items(graph->items, graph->space_items);
3622 }
3623
3624 graph->num_items = idx + 1;
3625 }
3626
3627 update_succeeded = update_io_graph_item(graph->items, idx, pinfo, edt, graph->hf_index, graph->calc_type, graph->interval);
3628 /* XXX - TAP_PACKET_FAILED if the item couldn't be updated, with an error message? */
3629 return update_succeeded ? TAP_PACKET_REDRAW : TAP_PACKET_DONT_REDRAW;
3630 }
3631
3632 /**
3633 * sharkd_session_process_iograph()
3634 *
3635 * Process iograph request
3636 *
3637 * Input:
3638 * (o) interval - interval time in ms, if not specified: 1000ms
3639 * (m) graph0 - First graph request
3640 * (o) graph1...graph9 - Other graph requests
3641 * (o) filter0 - First graph filter
3642 * (o) filter1...filter9 - Other graph filters
3643 *
3644 * Graph requests can be one of: "packets", "bytes", "bits", "sum:<field>", "frames:<field>", "max:<field>", "min:<field>", "avg:<field>", "load:<field>",
3645 * if you use variant with <field>, you need to pass field name in filter request.
3646 *
3647 * Output object with attributes:
3648 * (m) iograph - array of graph results with attributes:
3649 * errmsg - graph cannot be constructed
3650 * items - graph values, zeros are skipped, if value is not a number it's next index encoded as hex string
3651 */
3652 static void
sharkd_session_process_iograph(char * buf,const jsmntok_t * tokens,int count)3653 sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count)
3654 {
3655 const char *tok_interval = json_find_attr(buf, tokens, count, "interval");
3656 struct sharkd_iograph graphs[10];
3657 gboolean is_any_ok = FALSE;
3658 int graph_count;
3659
3660 guint32 interval_ms = 1000; /* default: one per second */
3661 int i;
3662
3663 if (tok_interval)
3664 ws_strtou32(tok_interval, NULL, &interval_ms);
3665
3666 for (i = graph_count = 0; i < (int) G_N_ELEMENTS(graphs); i++)
3667 {
3668 struct sharkd_iograph *graph = &graphs[graph_count];
3669
3670 const char *tok_graph;
3671 const char *tok_filter;
3672 char tok_format_buf[32];
3673 const char *field_name;
3674
3675 snprintf(tok_format_buf, sizeof(tok_format_buf), "graph%d", i);
3676 tok_graph = json_find_attr(buf, tokens, count, tok_format_buf);
3677 if (!tok_graph)
3678 break;
3679
3680 snprintf(tok_format_buf, sizeof(tok_format_buf), "filter%d", i);
3681 tok_filter = json_find_attr(buf, tokens, count, tok_format_buf);
3682
3683 if (!strcmp(tok_graph, "packets"))
3684 graph->calc_type = IOG_ITEM_UNIT_PACKETS;
3685 else if (!strcmp(tok_graph, "bytes"))
3686 graph->calc_type = IOG_ITEM_UNIT_BYTES;
3687 else if (!strcmp(tok_graph, "bits"))
3688 graph->calc_type = IOG_ITEM_UNIT_BITS;
3689 else if (g_str_has_prefix(tok_graph, "sum:"))
3690 graph->calc_type = IOG_ITEM_UNIT_CALC_SUM;
3691 else if (g_str_has_prefix(tok_graph, "frames:"))
3692 graph->calc_type = IOG_ITEM_UNIT_CALC_FRAMES;
3693 else if (g_str_has_prefix(tok_graph, "fields:"))
3694 graph->calc_type = IOG_ITEM_UNIT_CALC_FIELDS;
3695 else if (g_str_has_prefix(tok_graph, "max:"))
3696 graph->calc_type = IOG_ITEM_UNIT_CALC_MAX;
3697 else if (g_str_has_prefix(tok_graph, "min:"))
3698 graph->calc_type = IOG_ITEM_UNIT_CALC_MIN;
3699 else if (g_str_has_prefix(tok_graph, "avg:"))
3700 graph->calc_type = IOG_ITEM_UNIT_CALC_AVERAGE;
3701 else if (g_str_has_prefix(tok_graph, "load:"))
3702 graph->calc_type = IOG_ITEM_UNIT_CALC_LOAD;
3703 else
3704 break;
3705
3706 field_name = strchr(tok_graph, ':');
3707 if (field_name)
3708 field_name = field_name + 1;
3709
3710 graph->interval = interval_ms;
3711
3712 graph->hf_index = -1;
3713 graph->error = check_field_unit(field_name, &graph->hf_index, graph->calc_type);
3714
3715 graph->space_items = 0; /* TODO, can avoid realloc()s in sharkd_iograph_packet() by calculating: capture_time / interval */
3716 graph->num_items = 0;
3717 graph->items = NULL;
3718
3719 if (!graph->error)
3720 graph->error = register_tap_listener("frame", graph, tok_filter, TL_REQUIRES_PROTO_TREE, NULL, sharkd_iograph_packet, NULL, NULL);
3721
3722 graph_count++;
3723
3724 if (graph->error)
3725 {
3726 sharkd_json_error(
3727 rpcid, -6001, NULL,
3728 "%s", graph->error->str
3729 );
3730 g_string_free(graph->error, TRUE);
3731 return;
3732 }
3733
3734 if (graph->error == NULL)
3735 is_any_ok = TRUE;
3736 }
3737
3738 /* retap only if we have at least one ok */
3739 if (is_any_ok)
3740 sharkd_retap();
3741
3742 sharkd_json_result_prologue(rpcid);
3743
3744 sharkd_json_array_open("iograph");
3745 for (i = 0; i < graph_count; i++)
3746 {
3747 struct sharkd_iograph *graph = &graphs[i];
3748
3749 json_dumper_begin_object(&dumper);
3750
3751 if (graph->error)
3752 {
3753 fprintf(stderr, "SNAP 6002 - we should never get to here.\n");
3754 g_string_free(graph->error, TRUE);
3755 exit(-1);
3756 }
3757 else
3758 {
3759 int idx;
3760 int next_idx = 0;
3761
3762 sharkd_json_array_open("items");
3763 for (idx = 0; idx < graph->num_items; idx++)
3764 {
3765 double val;
3766
3767 val = get_io_graph_item(graph->items, graph->calc_type, idx, graph->hf_index, &cfile, graph->interval, graph->num_items);
3768
3769 /* if it's zero, don't display */
3770 if (val == 0.0)
3771 continue;
3772
3773 /* cause zeros are not printed, need to output index */
3774 if (next_idx != idx)
3775 sharkd_json_value_stringf(NULL, "%x", idx);
3776
3777 sharkd_json_value_anyf(NULL, "%f", val);
3778 next_idx = idx + 1;
3779 }
3780 sharkd_json_array_close();
3781 }
3782 json_dumper_end_object(&dumper);
3783
3784 remove_tap_listener(graph);
3785 g_free(graph->items);
3786 }
3787 sharkd_json_array_close();
3788
3789 sharkd_json_result_epilogue();
3790 }
3791
3792 /**
3793 * sharkd_session_process_intervals()
3794 *
3795 * Process intervals request - generate basic capture file statistics per requested interval.
3796 *
3797 * Input:
3798 * (o) interval - interval time in ms, if not specified: 1000ms
3799 * (o) filter - filter for generating interval request
3800 *
3801 * Output object with attributes:
3802 * (m) intervals - array of intervals, with indexes:
3803 * [0] - index of interval,
3804 * [1] - number of frames during interval,
3805 * [2] - number of bytes during interval.
3806 *
3807 * (m) last - last interval number.
3808 * (m) frames - total number of frames
3809 * (m) bytes - total number of bytes
3810 *
3811 * NOTE: If frames are not in order, there might be items with same interval index, or even negative one.
3812 */
3813 static void
sharkd_session_process_intervals(char * buf,const jsmntok_t * tokens,int count)3814 sharkd_session_process_intervals(char *buf, const jsmntok_t *tokens, int count)
3815 {
3816 const char *tok_interval = json_find_attr(buf, tokens, count, "interval");
3817 const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
3818
3819 const guint8 *filter_data = NULL;
3820
3821 struct
3822 {
3823 unsigned int frames;
3824 guint64 bytes;
3825 } st, st_total;
3826
3827 nstime_t *start_ts;
3828
3829 guint32 interval_ms = 1000; /* default: one per second */
3830
3831 gint64 idx;
3832 gint64 max_idx = 0;
3833
3834 if (tok_interval)
3835 ws_strtou32(tok_interval, NULL, &interval_ms); // already validated
3836
3837 if (tok_filter)
3838 {
3839 const struct sharkd_filter_item *filter_item;
3840
3841 filter_item = sharkd_session_filter_data(tok_filter);
3842 if (!filter_item)
3843 {
3844 sharkd_json_error(
3845 rpcid, -7001, NULL,
3846 "Invalid filter parameter: %s", tok_filter
3847 );
3848 return;
3849 }
3850 filter_data = filter_item->filtered;
3851 }
3852
3853 st_total.frames = 0;
3854 st_total.bytes = 0;
3855
3856 st.frames = 0;
3857 st.bytes = 0;
3858
3859 idx = 0;
3860
3861 sharkd_json_result_prologue(rpcid);
3862 sharkd_json_array_open("intervals");
3863
3864 start_ts = (cfile.count >= 1) ? &(sharkd_get_frame(1)->abs_ts) : NULL;
3865
3866 for (guint32 framenum = 1; framenum <= cfile.count; framenum++)
3867 {
3868 frame_data *fdata;
3869 gint64 msec_rel;
3870 gint64 new_idx;
3871
3872 if (filter_data && !(filter_data[framenum / 8] & (1 << (framenum % 8))))
3873 continue;
3874
3875 fdata = sharkd_get_frame(framenum);
3876
3877 msec_rel = (fdata->abs_ts.secs - start_ts->secs) * (gint64) 1000 + (fdata->abs_ts.nsecs - start_ts->nsecs) / 1000000;
3878 new_idx = msec_rel / interval_ms;
3879
3880 if (idx != new_idx)
3881 {
3882 if (st.frames != 0)
3883 {
3884 sharkd_json_value_anyf(NULL, "[%" G_GINT64_FORMAT ",%u,%" G_GUINT64_FORMAT "]", idx, st.frames, st.bytes);
3885 }
3886
3887 idx = new_idx;
3888 if (idx > max_idx)
3889 max_idx = idx;
3890
3891 st.frames = 0;
3892 st.bytes = 0;
3893 }
3894
3895 st.frames += 1;
3896 st.bytes += fdata->pkt_len;
3897
3898 st_total.frames += 1;
3899 st_total.bytes += fdata->pkt_len;
3900 }
3901
3902 if (st.frames != 0)
3903 {
3904 sharkd_json_value_anyf(NULL, "[%" G_GINT64_FORMAT ",%u,%" G_GUINT64_FORMAT "]", idx, st.frames, st.bytes);
3905 }
3906 sharkd_json_array_close();
3907
3908 sharkd_json_value_anyf("last", "%" G_GINT64_FORMAT, max_idx);
3909 sharkd_json_value_anyf("frames", "%u", st_total.frames);
3910 sharkd_json_value_anyf("bytes", "%" G_GUINT64_FORMAT, st_total.bytes);
3911
3912 sharkd_json_result_epilogue();
3913 }
3914
3915 /**
3916 * sharkd_session_process_frame()
3917 *
3918 * Process frame request
3919 *
3920 * Input:
3921 * (m) frame - requested frame number
3922 * (o) ref_frame - time reference frame number
3923 * (o) prev_frame - previously displayed frame number
3924 * (o) proto - set if output frame tree
3925 * (o) columns - set if output frame columns
3926 * (o) color - set if output color-filter bg/fg
3927 * (o) bytes - set if output frame bytes
3928 * (o) hidden - set if output hidden tree fields
3929 *
3930 * Output object with attributes:
3931 * (m) err - 0 if succeed
3932 * (o) tree - array of frame nodes with attributes:
3933 * l - label
3934 * t: 'proto', 'framenum', 'url' - type of node
3935 * f - filter string
3936 * s - severity
3937 * e - subtree ett index
3938 * n - array of subtree nodes
3939 * h - two item array: (item start, item length)
3940 * i - two item array: (appendix start, appendix length)
3941 * p - [RESERVED] two item array: (protocol start, protocol length)
3942 * ds- data src index
3943 * url - only for t:'url', url
3944 * fnum - only for t:'framenum', frame number
3945 * g - if field is generated by Wireshark
3946 * v - if field is hidden
3947 *
3948 * (o) col - array of column data
3949 * (o) bytes - base64 of frame bytes
3950 * (o) ds - array of other data srcs
3951 * (o) comment - frame comment
3952 * (o) fol - array of follow filters:
3953 * [0] - protocol
3954 * [1] - filter string
3955 * (o) i - if frame is ignored
3956 * (o) m - if frame is marked
3957 * (o) bg - color filter - background color in hex
3958 * (o) fg - color filter - foreground color in hex
3959 */
3960 static void
sharkd_session_process_frame(char * buf,const jsmntok_t * tokens,int count)3961 sharkd_session_process_frame(char *buf, const jsmntok_t *tokens, int count)
3962 {
3963 const char *tok_frame = json_find_attr(buf, tokens, count, "frame");
3964 const char *tok_ref_frame = json_find_attr(buf, tokens, count, "ref_frame");
3965 const char *tok_prev_frame = json_find_attr(buf, tokens, count, "prev_frame");
3966 column_info *cinfo = NULL;
3967
3968 guint32 framenum, ref_frame_num, prev_dis_num;
3969 guint32 dissect_flags = SHARKD_DISSECT_FLAG_NULL;
3970 struct sharkd_frame_request_data req_data;
3971 wtap_rec rec; /* Record metadata */
3972 Buffer rec_buf; /* Record data */
3973 enum dissect_request_status status;
3974 int err;
3975 gchar *err_info;
3976
3977 ws_strtou32(tok_frame, NULL, &framenum); // we have already validated this
3978
3979 ref_frame_num = (framenum != 1) ? 1 : 0;
3980 if (tok_ref_frame)
3981 {
3982 ws_strtou32(tok_ref_frame, NULL, &ref_frame_num);
3983 if (ref_frame_num > framenum)
3984 {
3985 sharkd_json_error(
3986 rpcid, -8001, NULL,
3987 "Invalid ref_frame - The ref_frame occurs after the frame specified"
3988 );
3989 return;
3990 }
3991 }
3992
3993 prev_dis_num = framenum - 1;
3994 if (tok_prev_frame)
3995 {
3996 ws_strtou32(tok_prev_frame, NULL, &prev_dis_num);
3997 if (prev_dis_num >= framenum)
3998 {
3999 sharkd_json_error(
4000 rpcid, -8002, NULL,
4001 "Invalid prev_frame - The prev_frame occurs on or after the frame specified"
4002 );
4003 return;
4004 }
4005 }
4006
4007 if (json_find_attr(buf, tokens, count, "proto") != NULL)
4008 dissect_flags |= SHARKD_DISSECT_FLAG_PROTO_TREE;
4009 if (json_find_attr(buf, tokens, count, "bytes") != NULL)
4010 dissect_flags |= SHARKD_DISSECT_FLAG_BYTES;
4011 if (json_find_attr(buf, tokens, count, "columns") != NULL) {
4012 dissect_flags |= SHARKD_DISSECT_FLAG_COLUMNS;
4013 cinfo = &cfile.cinfo;
4014 }
4015 if (json_find_attr(buf, tokens, count, "color") != NULL)
4016 dissect_flags |= SHARKD_DISSECT_FLAG_COLOR;
4017
4018 req_data.display_hidden = (json_find_attr(buf, tokens, count, "v") != NULL);
4019
4020 wtap_rec_init(&rec);
4021 ws_buffer_init(&rec_buf, 1514);
4022
4023 status = sharkd_dissect_request(framenum, ref_frame_num, prev_dis_num,
4024 &rec, &rec_buf, cinfo, dissect_flags,
4025 &sharkd_session_process_frame_cb, &req_data, &err, &err_info);
4026 switch (status) {
4027
4028 case DISSECT_REQUEST_SUCCESS:
4029 /* success */
4030 break;
4031
4032 case DISSECT_REQUEST_NO_SUCH_FRAME:
4033 sharkd_json_error(
4034 rpcid, -8003, NULL,
4035 "Invalid frame - The frame number requested is out of range"
4036 );
4037 break;
4038
4039 case DISSECT_REQUEST_READ_ERROR:
4040 sharkd_json_error(
4041 rpcid, -8003, NULL,
4042 /* XXX - show the error details */
4043 "Read error - The frame could not be read from the file"
4044 );
4045 g_free(err_info);
4046 break;
4047 }
4048
4049 wtap_rec_cleanup(&rec);
4050 ws_buffer_free(&rec_buf);
4051 }
4052
4053 /**
4054 * sharkd_session_process_check()
4055 *
4056 * Process check request.
4057 *
4058 * Input:
4059 * (o) filter - filter to be checked
4060 * (o) field - field to be checked
4061 *
4062 * Output object with attributes:
4063 * (m) err - always 0
4064 * (o) filter - 'ok', 'warn' or error message
4065 * (o) field - 'ok', or 'notfound'
4066 */
4067 static int
sharkd_session_process_check(char * buf,const jsmntok_t * tokens,int count)4068 sharkd_session_process_check(char *buf, const jsmntok_t *tokens, int count)
4069 {
4070 const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
4071 const char *tok_field = json_find_attr(buf, tokens, count, "field");
4072
4073 if (tok_filter != NULL)
4074 {
4075 char *err_msg = NULL;
4076 dfilter_t *dfp;
4077
4078 if (dfilter_compile(tok_filter, &dfp, &err_msg))
4079 {
4080 if (dfp && dfilter_deprecated_tokens(dfp))
4081 sharkd_json_warning(rpcid, err_msg);
4082 else
4083 sharkd_json_simple_ok(rpcid);
4084
4085 dfilter_free(dfp);
4086 g_free(err_msg);
4087 return 0;
4088 }
4089 else
4090 {
4091 sharkd_json_error(
4092 rpcid, -5001, NULL,
4093 "Filter invalid - %s", err_msg
4094 );
4095 return -5001;
4096 }
4097 }
4098
4099 if (tok_field != NULL)
4100 {
4101 header_field_info *hfi = proto_registrar_get_byname(tok_field);
4102
4103 if (!hfi)
4104 {
4105 sharkd_json_error(
4106 rpcid, -5002, NULL,
4107 "Field %s not found", tok_field
4108 );
4109 return -5002;
4110 }
4111 else
4112 {
4113 sharkd_json_simple_ok(rpcid);
4114 return 0;
4115 }
4116 }
4117
4118 sharkd_json_simple_ok(rpcid);
4119 return 0;
4120 }
4121
4122 struct sharkd_session_process_complete_pref_data
4123 {
4124 const char *module;
4125 const char *pref;
4126 };
4127
4128 static guint
sharkd_session_process_complete_pref_cb(module_t * module,gpointer d)4129 sharkd_session_process_complete_pref_cb(module_t *module, gpointer d)
4130 {
4131 struct sharkd_session_process_complete_pref_data *data = (struct sharkd_session_process_complete_pref_data *) d;
4132
4133 if (strncmp(data->pref, module->name, strlen(data->pref)) != 0)
4134 return 0;
4135
4136 json_dumper_begin_object(&dumper);
4137 sharkd_json_value_string("f", module->name);
4138 sharkd_json_value_string("d", module->title);
4139 json_dumper_end_object(&dumper);
4140
4141 return 0;
4142 }
4143
4144 static guint
sharkd_session_process_complete_pref_option_cb(pref_t * pref,gpointer d)4145 sharkd_session_process_complete_pref_option_cb(pref_t *pref, gpointer d)
4146 {
4147 struct sharkd_session_process_complete_pref_data *data = (struct sharkd_session_process_complete_pref_data *) d;
4148 const char *pref_name = prefs_get_name(pref);
4149 const char *pref_title = prefs_get_title(pref);
4150
4151 if (strncmp(data->pref, pref_name, strlen(data->pref)) != 0)
4152 return 0;
4153
4154 json_dumper_begin_object(&dumper);
4155 sharkd_json_value_stringf("f", "%s.%s", data->module, pref_name);
4156 sharkd_json_value_string("d", pref_title);
4157 json_dumper_end_object(&dumper);
4158
4159 return 0; /* continue */
4160 }
4161
4162 /**
4163 * sharkd_session_process_complete()
4164 *
4165 * Process complete request
4166 *
4167 * Input:
4168 * (o) field - field to be completed
4169 * (o) pref - preference to be completed
4170 *
4171 * Output object with attributes:
4172 * (m) err - always 0
4173 * (o) field - array of object with attributes:
4174 * (m) f - field text
4175 * (o) t - field type (FT_ number)
4176 * (o) n - field name
4177 * (o) pref - array of object with attributes:
4178 * (m) f - pref name
4179 * (o) d - pref description
4180 */
4181 static int
sharkd_session_process_complete(char * buf,const jsmntok_t * tokens,int count)4182 sharkd_session_process_complete(char *buf, const jsmntok_t *tokens, int count)
4183 {
4184 const char *tok_field = json_find_attr(buf, tokens, count, "field");
4185 const char *tok_pref = json_find_attr(buf, tokens, count, "pref");
4186
4187 sharkd_json_result_prologue(rpcid);
4188
4189 if (tok_field != NULL && tok_field[0])
4190 {
4191 const size_t filter_length = strlen(tok_field);
4192 const int filter_with_dot = !!strchr(tok_field, '.');
4193
4194 void *proto_cookie;
4195 void *field_cookie;
4196 int proto_id;
4197
4198 sharkd_json_array_open("field");
4199
4200 for (proto_id = proto_get_first_protocol(&proto_cookie); proto_id != -1; proto_id = proto_get_next_protocol(&proto_cookie))
4201 {
4202 protocol_t *protocol = find_protocol_by_id(proto_id);
4203 const char *protocol_filter;
4204 const char *protocol_name;
4205 header_field_info *hfinfo;
4206
4207 if (!proto_is_protocol_enabled(protocol))
4208 continue;
4209
4210 protocol_name = proto_get_protocol_long_name(protocol);
4211 protocol_filter = proto_get_protocol_filter_name(proto_id);
4212
4213 if (strlen(protocol_filter) >= filter_length && !g_ascii_strncasecmp(tok_field, protocol_filter, filter_length))
4214 {
4215 json_dumper_begin_object(&dumper);
4216 {
4217 sharkd_json_value_string("f", protocol_filter);
4218 sharkd_json_value_anyf("t", "%d", FT_PROTOCOL);
4219 sharkd_json_value_string("n", protocol_name);
4220 }
4221 json_dumper_end_object(&dumper);
4222 }
4223
4224 if (!filter_with_dot)
4225 continue;
4226
4227 for (hfinfo = proto_get_first_protocol_field(proto_id, &field_cookie); hfinfo != NULL; hfinfo = proto_get_next_protocol_field(proto_id, &field_cookie))
4228 {
4229 if (hfinfo->same_name_prev_id != -1) /* ignore duplicate names */
4230 continue;
4231
4232 if (strlen(hfinfo->abbrev) >= filter_length && !g_ascii_strncasecmp(tok_field, hfinfo->abbrev, filter_length))
4233 {
4234 json_dumper_begin_object(&dumper);
4235 {
4236 sharkd_json_value_string("f", hfinfo->abbrev);
4237
4238 /* XXX, skip displaying name, if there are multiple (to not confuse user) */
4239 if (hfinfo->same_name_next == NULL)
4240 {
4241 sharkd_json_value_anyf("t", "%d", hfinfo->type);
4242 sharkd_json_value_string("n", hfinfo->name);
4243 }
4244 }
4245 json_dumper_end_object(&dumper);
4246 }
4247 }
4248 }
4249
4250 sharkd_json_array_close();
4251 }
4252
4253 if (tok_pref != NULL && tok_pref[0])
4254 {
4255 struct sharkd_session_process_complete_pref_data data;
4256 char *dot_sepa;
4257
4258 data.module = tok_pref;
4259 data.pref = tok_pref;
4260
4261 sharkd_json_array_open("pref");
4262 if ((dot_sepa = strchr(tok_pref, '.')))
4263 {
4264 module_t *pref_mod;
4265
4266 *dot_sepa = '\0'; /* XXX, C abuse: discarding-const */
4267 data.pref = dot_sepa + 1;
4268
4269 pref_mod = prefs_find_module(data.module);
4270 if (pref_mod)
4271 prefs_pref_foreach(pref_mod, sharkd_session_process_complete_pref_option_cb, &data);
4272
4273 *dot_sepa = '.';
4274 }
4275 else
4276 {
4277 prefs_modules_foreach(sharkd_session_process_complete_pref_cb, &data);
4278 }
4279 sharkd_json_array_close();
4280 }
4281
4282 sharkd_json_result_epilogue();
4283
4284 return 0;
4285 }
4286
4287 /**
4288 * sharkd_session_process_setcomment()
4289 *
4290 * Process setcomment request
4291 *
4292 * Input:
4293 * (m) frame - frame number
4294 * (o) comment - user comment
4295 *
4296 * Output object with attributes:
4297 * (m) err - error code: 0 succeed
4298 *
4299 * Note:
4300 * For now, adds comments, doesn't remove or replace them.
4301 */
4302 static void
sharkd_session_process_setcomment(char * buf,const jsmntok_t * tokens,int count)4303 sharkd_session_process_setcomment(char *buf, const jsmntok_t *tokens, int count)
4304 {
4305 const char *tok_frame = json_find_attr(buf, tokens, count, "frame");
4306 const char *tok_comment = json_find_attr(buf, tokens, count, "comment");
4307
4308 guint32 framenum;
4309 frame_data *fdata;
4310 wtap_opttype_return_val ret;
4311 wtap_block_t pkt_block = NULL;
4312
4313 if (!tok_frame || !ws_strtou32(tok_frame, NULL, &framenum) || framenum == 0)
4314 {
4315 sharkd_json_error(
4316 rpcid, -3001, NULL,
4317 "Frame number must be a positive integer"
4318 );
4319 return;
4320 }
4321
4322 fdata = sharkd_get_frame(framenum); // BUG HERE - If no file loaded you get a crash
4323 if (!fdata)
4324 {
4325 sharkd_json_error(
4326 rpcid, -3002, NULL,
4327 "Frame number is out of range"
4328 );
4329 return;
4330 }
4331
4332 pkt_block = sharkd_get_packet_block(fdata);
4333
4334 ret = wtap_block_add_string_option(pkt_block, OPT_COMMENT, tok_comment, strlen(tok_comment));
4335
4336 if (ret != WTAP_OPTTYPE_SUCCESS)
4337 {
4338 sharkd_json_error(
4339 rpcid, -3003, NULL,
4340 "Unable to set the comment"
4341 );
4342 }
4343 else
4344 {
4345 sharkd_set_modified_block(fdata, pkt_block);
4346 sharkd_json_simple_ok(rpcid);
4347 }
4348 }
4349
4350 /**
4351 * sharkd_session_process_setconf()
4352 *
4353 * Process setconf request
4354 *
4355 * Input:
4356 * (m) name - preference name
4357 * (m) value - preference value
4358 *
4359 * Output object with attributes:
4360 * (m) err - error code: 0 succeed
4361 */
4362 static void
sharkd_session_process_setconf(char * buf,const jsmntok_t * tokens,int count)4363 sharkd_session_process_setconf(char *buf, const jsmntok_t *tokens, int count)
4364 {
4365 const char *tok_name = json_find_attr(buf, tokens, count, "name");
4366 const char *tok_value = json_find_attr(buf, tokens, count, "value");
4367 char pref[4096];
4368 char *errmsg = NULL;
4369
4370 prefs_set_pref_e ret;
4371
4372 if (!tok_name || tok_name[0] == '\0')
4373 {
4374 sharkd_json_error(
4375 rpcid, -4001, NULL,
4376 "Preference name missing"
4377 );
4378 return;
4379 }
4380
4381 if (!tok_value)
4382 {
4383 sharkd_json_error(
4384 rpcid, -4002, NULL,
4385 "Preference value missing"
4386 );
4387 return;
4388 }
4389
4390 snprintf(pref, sizeof(pref), "%s:%s", tok_name, tok_value);
4391
4392 ret = prefs_set_pref(pref, &errmsg);
4393
4394 switch (ret)
4395 {
4396 case PREFS_SET_OK:
4397 sharkd_json_simple_ok(rpcid);
4398 break;
4399
4400 case PREFS_SET_OBSOLETE:
4401 sharkd_json_error(
4402 rpcid, -4003, NULL,
4403 "The preference specified is obsolete"
4404 );
4405 break;
4406
4407 case PREFS_SET_NO_SUCH_PREF:
4408 sharkd_json_error(
4409 rpcid, -4004, NULL,
4410 "No such preference exists"
4411 );
4412 break;
4413
4414 default:
4415 sharkd_json_error(
4416 rpcid, -4005, NULL,
4417 "Unable to set the preference"
4418 );
4419 }
4420
4421 g_free(errmsg);
4422 }
4423
4424 struct sharkd_session_process_dumpconf_data
4425 {
4426 module_t *module;
4427 };
4428
4429 static guint
sharkd_session_process_dumpconf_cb(pref_t * pref,gpointer d)4430 sharkd_session_process_dumpconf_cb(pref_t *pref, gpointer d)
4431 {
4432 struct sharkd_session_process_dumpconf_data *data = (struct sharkd_session_process_dumpconf_data *) d;
4433 const char *pref_name = prefs_get_name(pref);
4434
4435 char json_pref_key[512];
4436
4437 snprintf(json_pref_key, sizeof(json_pref_key), "%s.%s", data->module->name, pref_name);
4438 json_dumper_set_member_name(&dumper, json_pref_key);
4439 json_dumper_begin_object(&dumper);
4440
4441 switch (prefs_get_type(pref))
4442 {
4443 case PREF_UINT:
4444 case PREF_DECODE_AS_UINT:
4445 sharkd_json_value_anyf("u", "%u", prefs_get_uint_value_real(pref, pref_current));
4446 if (prefs_get_uint_base(pref) != 10)
4447 sharkd_json_value_anyf("ub", "%u", prefs_get_uint_base(pref));
4448 break;
4449
4450 case PREF_BOOL:
4451 sharkd_json_value_anyf("b", prefs_get_bool_value(pref, pref_current) ? "1" : "0");
4452 break;
4453
4454 case PREF_STRING:
4455 case PREF_SAVE_FILENAME:
4456 case PREF_OPEN_FILENAME:
4457 case PREF_DIRNAME:
4458 sharkd_json_value_string("s", prefs_get_string_value(pref, pref_current));
4459 break;
4460
4461 case PREF_ENUM:
4462 {
4463 const enum_val_t *enums;
4464
4465 sharkd_json_array_open("e");
4466 for (enums = prefs_get_enumvals(pref); enums->name; enums++)
4467 {
4468 json_dumper_begin_object(&dumper);
4469
4470 sharkd_json_value_anyf("v", "%d", enums->value);
4471
4472 if (enums->value == prefs_get_enum_value(pref, pref_current))
4473 sharkd_json_value_anyf("s", "1");
4474
4475 sharkd_json_value_string("d", enums->description);
4476
4477 json_dumper_end_object(&dumper);
4478 }
4479 sharkd_json_array_close();
4480 break;
4481 }
4482
4483 case PREF_RANGE:
4484 case PREF_DECODE_AS_RANGE:
4485 {
4486 char *range_str = range_convert_range(NULL, prefs_get_range_value_real(pref, pref_current));
4487 sharkd_json_value_string("r", range_str);
4488 wmem_free(NULL, range_str);
4489 break;
4490 }
4491
4492 case PREF_UAT:
4493 {
4494 uat_t *uat = prefs_get_uat_value(pref);
4495 guint idx;
4496
4497 sharkd_json_array_open("t");
4498 for (idx = 0; idx < uat->raw_data->len; idx++)
4499 {
4500 void *rec = UAT_INDEX_PTR(uat, idx);
4501 guint colnum;
4502
4503 sharkd_json_array_open(NULL);
4504 for (colnum = 0; colnum < uat->ncols; colnum++)
4505 {
4506 char *str = uat_fld_tostr(rec, &(uat->fields[colnum]));
4507
4508 sharkd_json_value_string(NULL, str);
4509 g_free(str);
4510 }
4511
4512 sharkd_json_array_close();
4513 }
4514
4515 sharkd_json_array_close();
4516 break;
4517 }
4518
4519 case PREF_COLOR:
4520 case PREF_CUSTOM:
4521 case PREF_STATIC_TEXT:
4522 case PREF_OBSOLETE:
4523 /* TODO */
4524 break;
4525 }
4526
4527 #if 0
4528 sharkd_json_value_string("t", prefs_get_title(pref));
4529 #endif
4530
4531 json_dumper_end_object(&dumper);
4532
4533 return 0; /* continue */
4534 }
4535
4536 static guint
sharkd_session_process_dumpconf_mod_cb(module_t * module,gpointer d)4537 sharkd_session_process_dumpconf_mod_cb(module_t *module, gpointer d)
4538 {
4539 struct sharkd_session_process_dumpconf_data *data = (struct sharkd_session_process_dumpconf_data *) d;
4540
4541 data->module = module;
4542 prefs_pref_foreach(module, sharkd_session_process_dumpconf_cb, data);
4543
4544 return 0;
4545 }
4546
4547 /**
4548 * sharkd_session_process_dumpconf()
4549 *
4550 * Process dumpconf request
4551 *
4552 * Input:
4553 * (o) pref - module, or preference, NULL for all
4554 *
4555 * Output object with attributes:
4556 * (o) prefs - object with module preferences
4557 * (m) [KEY] - preference name
4558 * (o) u - preference value (for PREF_UINT, PREF_DECODE_AS_UINT)
4559 * (o) ub - preference value suggested base for display (for PREF_UINT, PREF_DECODE_AS_UINT) and if different than 10
4560 * (o) b - preference value (only for PREF_BOOL) (1 true, 0 false)
4561 * (o) s - preference value (for PREF_STRING, PREF_SAVE_FILENAME, PREF_OPEN_FILENAME, PREF_DIRNAME)
4562 * (o) e - preference possible values (only for PREF_ENUM)
4563 * (o) r - preference value (for PREF_RANGE, PREF_DECODE_AS_RANGE)
4564 * (o) t - preference value (only for PREF_UAT)
4565 */
4566 static void
sharkd_session_process_dumpconf(char * buf,const jsmntok_t * tokens,int count)4567 sharkd_session_process_dumpconf(char *buf, const jsmntok_t *tokens, int count)
4568 {
4569 const char *tok_pref = json_find_attr(buf, tokens, count, "pref");
4570 module_t *pref_mod;
4571 char *dot_sepa;
4572
4573 if (!tok_pref)
4574 {
4575 struct sharkd_session_process_dumpconf_data data;
4576
4577 data.module = NULL;
4578
4579 sharkd_json_result_prologue(rpcid);
4580
4581 sharkd_json_value_anyf("prefs", NULL);
4582 json_dumper_begin_object(&dumper);
4583 prefs_modules_foreach(sharkd_session_process_dumpconf_mod_cb, &data);
4584 json_dumper_end_object(&dumper);
4585
4586 sharkd_json_result_epilogue();
4587 return;
4588 }
4589
4590 if ((dot_sepa = strchr(tok_pref, '.')))
4591 {
4592 pref_t *pref = NULL;
4593
4594 *dot_sepa = '\0'; /* XXX, C abuse: discarding-const */
4595 pref_mod = prefs_find_module(tok_pref);
4596 if (pref_mod)
4597 pref = prefs_find_preference(pref_mod, dot_sepa + 1);
4598 *dot_sepa = '.';
4599
4600 if (pref)
4601 {
4602 struct sharkd_session_process_dumpconf_data data;
4603
4604 data.module = pref_mod;
4605
4606 sharkd_json_result_prologue(rpcid);
4607
4608 sharkd_json_value_anyf("prefs", NULL);
4609 json_dumper_begin_object(&dumper);
4610 sharkd_session_process_dumpconf_cb(pref, &data);
4611 json_dumper_end_object(&dumper);
4612
4613 sharkd_json_result_epilogue();
4614 return;
4615 }
4616 else
4617 {
4618 sharkd_json_error(
4619 rpcid, -9001, NULL,
4620 "Invalid pref %s.", tok_pref
4621 );
4622 return;
4623 }
4624
4625 }
4626
4627 pref_mod = prefs_find_module(tok_pref);
4628 if (pref_mod)
4629 {
4630 struct sharkd_session_process_dumpconf_data data;
4631
4632 data.module = pref_mod;
4633
4634 sharkd_json_result_prologue(rpcid);
4635
4636 sharkd_json_value_anyf("prefs", NULL);
4637 json_dumper_begin_object(&dumper);
4638 prefs_pref_foreach(pref_mod, sharkd_session_process_dumpconf_cb, &data);
4639 json_dumper_end_object(&dumper);
4640
4641 sharkd_json_result_epilogue();
4642 }
4643 else
4644 {
4645 sharkd_json_error(
4646 rpcid, -9002, NULL,
4647 "Invalid pref %s.", tok_pref
4648 );
4649 }
4650 }
4651
4652 struct sharkd_download_rtp
4653 {
4654 rtpstream_id_t id;
4655 GSList *packets;
4656 double start_time;
4657 };
4658
4659 static void
sharkd_rtp_download_free_items(void * ptr)4660 sharkd_rtp_download_free_items(void *ptr)
4661 {
4662 rtp_packet_t *rtp_packet = (rtp_packet_t *) ptr;
4663
4664 g_free(rtp_packet->info);
4665 g_free(rtp_packet->payload_data);
4666 g_free(rtp_packet);
4667 }
4668
4669 static void
sharkd_rtp_download_decode(struct sharkd_download_rtp * req)4670 sharkd_rtp_download_decode(struct sharkd_download_rtp *req)
4671 {
4672 /* based on RtpAudioStream::decode() 6e29d874f8b5e6ebc59f661a0bb0dab8e56f122a */
4673 /* TODO, for now only without silence (timing_mode_ = Uninterrupted) */
4674
4675 static const int sample_bytes_ = sizeof(SAMPLE) / sizeof(char);
4676
4677 guint32 audio_out_rate_ = 0;
4678 struct _GHashTable *decoders_hash_ = rtp_decoder_hash_table_new();
4679 struct SpeexResamplerState_ *audio_resampler_ = NULL;
4680
4681 gsize resample_buff_len = 0x1000;
4682 SAMPLE *resample_buff = (SAMPLE *) g_malloc(resample_buff_len);
4683 spx_uint32_t cur_in_rate = 0;
4684 char *write_buff = NULL;
4685 size_t write_bytes = 0;
4686 unsigned channels = 0;
4687 unsigned sample_rate = 0;
4688
4689 GSList *l;
4690
4691 for (l = req->packets; l; l = l->next)
4692 {
4693 rtp_packet_t *rtp_packet = (rtp_packet_t *) l->data;
4694
4695 SAMPLE *decode_buff = NULL;
4696 size_t decoded_bytes;
4697
4698 decoded_bytes = decode_rtp_packet(rtp_packet, &decode_buff, decoders_hash_, &channels, &sample_rate);
4699 if (decoded_bytes == 0 || sample_rate == 0)
4700 {
4701 /* We didn't decode anything. Clean up and prep for the next packet. */
4702 g_free(decode_buff);
4703 continue;
4704 }
4705
4706 if (audio_out_rate_ == 0)
4707 {
4708 guint32 tmp32;
4709 guint16 tmp16;
4710 char wav_hdr[44];
4711
4712 /* First non-zero wins */
4713 audio_out_rate_ = sample_rate;
4714
4715 RTP_STREAM_DEBUG("Audio sample rate is %u", audio_out_rate_);
4716
4717 /* write WAVE header */
4718 memset(&wav_hdr, 0, sizeof(wav_hdr));
4719 memcpy(&wav_hdr[0], "RIFF", 4);
4720 memcpy(&wav_hdr[4], "\xFF\xFF\xFF\xFF", 4); /* XXX, unknown */
4721 memcpy(&wav_hdr[8], "WAVE", 4);
4722
4723 memcpy(&wav_hdr[12], "fmt ", 4);
4724 memcpy(&wav_hdr[16], "\x10\x00\x00\x00", 4); /* PCM */
4725 memcpy(&wav_hdr[20], "\x01\x00", 2); /* PCM */
4726 /* # channels */
4727 tmp16 = channels;
4728 memcpy(&wav_hdr[22], &tmp16, 2);
4729 /* sample rate */
4730 tmp32 = sample_rate;
4731 memcpy(&wav_hdr[24], &tmp32, 4);
4732 /* byte rate */
4733 tmp32 = sample_rate * channels * sample_bytes_;
4734 memcpy(&wav_hdr[28], &tmp32, 4);
4735 /* block align */
4736 tmp16 = channels * sample_bytes_;
4737 memcpy(&wav_hdr[32], &tmp16, 2);
4738 /* bits per sample */
4739 tmp16 = 8 * sample_bytes_;
4740 memcpy(&wav_hdr[34], &tmp16, 2);
4741
4742 memcpy(&wav_hdr[36], "data", 4);
4743 memcpy(&wav_hdr[40], "\xFF\xFF\xFF\xFF", 4); /* XXX, unknown */
4744
4745 json_dumper_write_base64(&dumper, wav_hdr, sizeof(wav_hdr));
4746 }
4747
4748 // Write samples to our file.
4749 write_buff = (char *) decode_buff;
4750 write_bytes = decoded_bytes;
4751
4752 if (audio_out_rate_ != sample_rate)
4753 {
4754 spx_uint32_t in_len, out_len;
4755
4756 /* Resample the audio to match our previous output rate. */
4757 if (!audio_resampler_)
4758 {
4759 audio_resampler_ = speex_resampler_init(1, sample_rate, audio_out_rate_, 10, NULL);
4760 speex_resampler_skip_zeros(audio_resampler_);
4761 RTP_STREAM_DEBUG("Started resampling from %u to (out) %u Hz.", sample_rate, audio_out_rate_);
4762 }
4763 else
4764 {
4765 spx_uint32_t audio_out_rate;
4766 speex_resampler_get_rate(audio_resampler_, &cur_in_rate, &audio_out_rate);
4767
4768 if (sample_rate != cur_in_rate)
4769 {
4770 speex_resampler_set_rate(audio_resampler_, sample_rate, audio_out_rate);
4771 RTP_STREAM_DEBUG("Changed input rate from %u to %u Hz. Out is %u.", cur_in_rate, sample_rate, audio_out_rate_);
4772 }
4773 }
4774 in_len = (spx_uint32_t)rtp_packet->info->info_payload_len;
4775 out_len = (audio_out_rate_ * (spx_uint32_t)rtp_packet->info->info_payload_len / sample_rate) + (audio_out_rate_ % sample_rate != 0);
4776 if (out_len * sample_bytes_ > resample_buff_len)
4777 {
4778 while ((out_len * sample_bytes_ > resample_buff_len))
4779 resample_buff_len *= 2;
4780 resample_buff = (SAMPLE *) g_realloc(resample_buff, resample_buff_len);
4781 }
4782
4783 speex_resampler_process_int(audio_resampler_, 0, decode_buff, &in_len, resample_buff, &out_len);
4784 write_buff = (char *) resample_buff;
4785 write_bytes = out_len * sample_bytes_;
4786 }
4787
4788 /* Write the decoded, possibly-resampled audio */
4789 json_dumper_write_base64(&dumper, write_buff, write_bytes);
4790
4791 g_free(decode_buff);
4792 }
4793
4794 g_free(resample_buff);
4795 g_hash_table_destroy(decoders_hash_);
4796 }
4797
4798 static tap_packet_status
sharkd_session_packet_download_tap_rtp_cb(void * tapdata,packet_info * pinfo,epan_dissect_t * edt _U_,const void * data)4799 sharkd_session_packet_download_tap_rtp_cb(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *data)
4800 {
4801 const struct _rtp_info *rtp_info = (const struct _rtp_info *) data;
4802 struct sharkd_download_rtp *req_rtp = (struct sharkd_download_rtp *) tapdata;
4803
4804 /* do not consider RTP packets without a setup frame */
4805 if (rtp_info->info_setup_frame_num == 0)
4806 return TAP_PACKET_DONT_REDRAW;
4807
4808 if (rtpstream_id_equal_pinfo_rtp_info(&req_rtp->id, pinfo, rtp_info))
4809 {
4810 rtp_packet_t *rtp_packet;
4811
4812 rtp_packet = g_new0(rtp_packet_t, 1);
4813 rtp_packet->info = (struct _rtp_info *) g_memdup2(rtp_info, sizeof(struct _rtp_info));
4814
4815 if (rtp_info->info_all_data_present && rtp_info->info_payload_len != 0)
4816 rtp_packet->payload_data = (guint8 *) g_memdup2(&(rtp_info->info_data[rtp_info->info_payload_offset]), rtp_info->info_payload_len);
4817
4818 if (!req_rtp->packets)
4819 req_rtp->start_time = nstime_to_sec(&pinfo->abs_ts);
4820
4821 rtp_packet->frame_num = pinfo->num;
4822 rtp_packet->arrive_offset = nstime_to_sec(&pinfo->abs_ts) - req_rtp->start_time;
4823
4824 /* XXX, O(n) optimize */
4825 req_rtp->packets = g_slist_append(req_rtp->packets, rtp_packet);
4826 }
4827
4828 return TAP_PACKET_DONT_REDRAW;
4829 }
4830
4831 /**
4832 * sharkd_session_process_download()
4833 *
4834 * Process download request
4835 *
4836 * Input:
4837 * (m) token - token to download
4838 *
4839 * Output object with attributes:
4840 * (o) file - suggested name of file
4841 * (o) mime - suggested content type
4842 * (o) data - payload base64 encoded
4843 */
4844 static void
sharkd_session_process_download(char * buf,const jsmntok_t * tokens,int count)4845 sharkd_session_process_download(char *buf, const jsmntok_t *tokens, int count)
4846 {
4847 const char *tok_token = json_find_attr(buf, tokens, count, "token");
4848
4849 if (!tok_token)
4850 return;
4851
4852 if (!strncmp(tok_token, "eo:", 3))
4853 {
4854 struct sharkd_export_object_list *object_list;
4855 const export_object_entry_t *eo_entry = NULL;
4856
4857 for (object_list = sharkd_eo_list; object_list; object_list = object_list->next)
4858 {
4859 size_t eo_type_len = strlen(object_list->type);
4860
4861 if (!strncmp(tok_token, object_list->type, eo_type_len) && tok_token[eo_type_len] == '_')
4862 {
4863 int row;
4864
4865 if (sscanf(&tok_token[eo_type_len + 1], "%d", &row) != 1)
4866 break;
4867
4868 eo_entry = (export_object_entry_t *) g_slist_nth_data(object_list->entries, row);
4869 break;
4870 }
4871 }
4872
4873 if (eo_entry)
4874 {
4875 const char *mime = (eo_entry->content_type) ? eo_entry->content_type : "application/octet-stream";
4876 const char *filename = (eo_entry->filename) ? eo_entry->filename : tok_token;
4877
4878 sharkd_json_result_prologue(rpcid);
4879 sharkd_json_value_string("file", filename);
4880 sharkd_json_value_string("mime", mime);
4881 sharkd_json_value_base64("data", eo_entry->payload_data, eo_entry->payload_len);
4882 sharkd_json_result_epilogue();
4883 }
4884 else
4885 {
4886 sharkd_json_result_prologue(rpcid);
4887 sharkd_json_result_epilogue();
4888 }
4889 }
4890 else if (!strcmp(tok_token, "ssl-secrets"))
4891 {
4892 gsize str_len;
4893 char *str = ssl_export_sessions(&str_len);
4894
4895 if (str)
4896 {
4897 const char *mime = "text/plain";
4898 const char *filename = "keylog.txt";
4899
4900 sharkd_json_result_prologue(rpcid);
4901 sharkd_json_value_string("file", filename);
4902 sharkd_json_value_string("mime", mime);
4903 sharkd_json_value_base64("data", str, str_len);
4904 sharkd_json_result_epilogue();
4905 }
4906 g_free(str);
4907 }
4908 else if (!strncmp(tok_token, "rtp:", 4))
4909 {
4910 struct sharkd_download_rtp rtp_req;
4911 GString *tap_error;
4912
4913 memset(&rtp_req, 0, sizeof(rtp_req));
4914 if (!sharkd_rtp_match_init(&rtp_req.id, tok_token + 4))
4915 {
4916 sharkd_json_error(
4917 rpcid, -10001, NULL,
4918 "sharkd_session_process_download() rtp tokenizing error %s", tok_token
4919 );
4920 return;
4921 }
4922
4923 tap_error = register_tap_listener("rtp", &rtp_req, NULL, 0, NULL, sharkd_session_packet_download_tap_rtp_cb, NULL, NULL);
4924 if (tap_error)
4925 {
4926 sharkd_json_error(
4927 rpcid, -10002, NULL,
4928 "sharkd_session_process_download() rtp error %s", tap_error->str
4929 );
4930 g_string_free(tap_error, TRUE);
4931 return;
4932 }
4933
4934 sharkd_retap();
4935 remove_tap_listener(&rtp_req);
4936
4937 if (rtp_req.packets)
4938 {
4939 const char *mime = "audio/x-wav";
4940 const char *filename = tok_token;
4941
4942 sharkd_json_result_prologue(rpcid);
4943 sharkd_json_value_string("file", filename);
4944 sharkd_json_value_string("mime", mime);
4945
4946 sharkd_json_value_anyf("data", NULL);
4947 json_dumper_begin_base64(&dumper);
4948 sharkd_rtp_download_decode(&rtp_req);
4949 json_dumper_end_base64(&dumper);
4950
4951 sharkd_json_result_epilogue();
4952
4953 g_slist_free_full(rtp_req.packets, sharkd_rtp_download_free_items);
4954 }
4955 }
4956 }
4957
4958 static void
sharkd_session_process(char * buf,const jsmntok_t * tokens,int count)4959 sharkd_session_process(char *buf, const jsmntok_t *tokens, int count)
4960 {
4961 if (json_prep(buf, tokens, count))
4962 {
4963 /* don't need [0] token */
4964 tokens++;
4965 count--;
4966
4967 const char* tok_method = json_find_attr(buf, tokens, count, "method");
4968
4969 if (!tok_method) {
4970 sharkd_json_error(
4971 rpcid, -32601, NULL,
4972 "No method found");
4973 return;
4974 }
4975 if (!strcmp(tok_method, "load"))
4976 sharkd_session_process_load(buf, tokens, count);
4977 else if (!strcmp(tok_method, "status"))
4978 sharkd_session_process_status();
4979 else if (!strcmp(tok_method, "analyse"))
4980 sharkd_session_process_analyse();
4981 else if (!strcmp(tok_method, "info"))
4982 sharkd_session_process_info();
4983 else if (!strcmp(tok_method, "check"))
4984 sharkd_session_process_check(buf, tokens, count);
4985 else if (!strcmp(tok_method, "complete"))
4986 sharkd_session_process_complete(buf, tokens, count);
4987 else if (!strcmp(tok_method, "frames"))
4988 sharkd_session_process_frames(buf, tokens, count);
4989 else if (!strcmp(tok_method, "tap"))
4990 sharkd_session_process_tap(buf, tokens, count);
4991 else if (!strcmp(tok_method, "follow"))
4992 sharkd_session_process_follow(buf, tokens, count);
4993 else if (!strcmp(tok_method, "iograph"))
4994 sharkd_session_process_iograph(buf, tokens, count);
4995 else if (!strcmp(tok_method, "intervals"))
4996 sharkd_session_process_intervals(buf, tokens, count);
4997 else if (!strcmp(tok_method, "frame"))
4998 sharkd_session_process_frame(buf, tokens, count);
4999 else if (!strcmp(tok_method, "setcomment"))
5000 sharkd_session_process_setcomment(buf, tokens, count);
5001 else if (!strcmp(tok_method, "setconf"))
5002 sharkd_session_process_setconf(buf, tokens, count);
5003 else if (!strcmp(tok_method, "dumpconf"))
5004 sharkd_session_process_dumpconf(buf, tokens, count);
5005 else if (!strcmp(tok_method, "download"))
5006 sharkd_session_process_download(buf, tokens, count);
5007 else if (!strcmp(tok_method, "bye"))
5008 {
5009 sharkd_json_simple_ok(rpcid);
5010 exit(0);
5011 }
5012 else
5013 {
5014 sharkd_json_error(
5015 rpcid, -32601, NULL,
5016 "The method \"%s\" is unknown", tok_method
5017 );
5018 }
5019 }
5020 }
5021
5022 int
sharkd_session_main(int mode_setting)5023 sharkd_session_main(int mode_setting)
5024 {
5025 char buf[2 * 1024];
5026 jsmntok_t *tokens = NULL;
5027 int tokens_max = -1;
5028
5029 mode = mode_setting;
5030
5031 fprintf(stderr, "Hello in child.\n");
5032
5033 dumper.output_file = stdout;
5034
5035 filter_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, sharkd_session_filter_free);
5036
5037 #ifdef HAVE_MAXMINDDB
5038 /* mmdbresolve was stopped before fork(), force starting it */
5039 uat_get_table_by_name("MaxMind Database Paths")->post_update_cb();
5040 #endif
5041
5042 while (fgets(buf, sizeof(buf), stdin))
5043 {
5044 /* every command is line seperated JSON */
5045 int ret;
5046
5047 ret = json_parse(buf, NULL, 0);
5048 if (ret <= 0)
5049 {
5050 sharkd_json_error(
5051 rpcid, -32600, NULL,
5052 "Invalid JSON(1)"
5053 );
5054 continue;
5055 }
5056
5057 /* fprintf(stderr, "JSON: %d tokens\n", ret); */
5058 ret += 1;
5059
5060 if (tokens == NULL || tokens_max < ret)
5061 {
5062 tokens_max = ret;
5063 tokens = (jsmntok_t *) g_realloc(tokens, sizeof(jsmntok_t) * tokens_max);
5064 }
5065
5066 memset(tokens, 0, ret * sizeof(jsmntok_t));
5067
5068 ret = json_parse(buf, tokens, ret);
5069 if (ret <= 0)
5070 {
5071 sharkd_json_error(
5072 rpcid, -32600, NULL,
5073 "Invalid JSON(2)"
5074 );
5075 continue;
5076 }
5077
5078 host_name_lookup_process();
5079
5080 sharkd_session_process(buf, tokens, ret);
5081 }
5082
5083 g_hash_table_destroy(filter_table);
5084 g_free(tokens);
5085
5086 return 0;
5087 }
5088
5089 /*
5090 * Editor modelines - https://www.wireshark.org/tools/modelines.html
5091 *
5092 * Local variables:
5093 * c-basic-offset: 8
5094 * tab-width: 8
5095 * indent-tabs-mode: t
5096 * End:
5097 *
5098 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
5099 * :indentSize=8:tabSize=8:noTabs=false:
5100 */
5101