Skip to content

Commit f331873

Browse files
authored
feat: add support for iograph (#18)
1 parent a1a0cbd commit f331873

File tree

9 files changed

+534
-164
lines changed

9 files changed

+534
-164
lines changed

lib/wiregasm/bindings.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ EMSCRIPTEN_BINDINGS(DissectSession)
3232
.function("getFrame", &DissectSession::getFrame)
3333
.function("tap", &DissectSession::tap)
3434
.function("download", &DissectSession::download)
35+
.function("iograph", &DissectSession::iograph)
3536
.function("follow", &DissectSession::follow);
3637
}
3738

@@ -198,9 +199,25 @@ EMSCRIPTEN_BINDINGS(CompleteField)
198199
.field("name", &CompleteField::name);
199200
}
200201

202+
EMSCRIPTEN_BINDINGS(IoGraph)
203+
{
204+
value_object<IoGraph>("IoGraph")
205+
.field("items", &IoGraph::items);
206+
}
207+
208+
EMSCRIPTEN_BINDINGS(IoGraphResult)
209+
{
210+
value_object<IoGraphResult>("IoGraphResult")
211+
.field("error", &IoGraphResult::error)
212+
.field("iograph", &IoGraphResult::iograph);
213+
214+
register_vector<IoGraph>("VectorIoGraph");
215+
}
216+
201217
EMSCRIPTEN_BINDINGS(stl_wrappers)
202218
{
203219
register_vector<string>("VectorString");
220+
register_vector<float>("VectorFloat");
204221
register_vector<FrameMeta>("VectorFrameMeta");
205222
register_vector<DataSource>("VectorDataSource");
206223
register_vector<ProtoTree>("VectorProtoTree");
@@ -303,6 +320,6 @@ EMSCRIPTEN_BINDINGS(ExportObject) {
303320
}
304321

305322

306-
EMSCRIPTEN_BINDINGS(TapInput) {
307-
register_map<string, string>("TapInput");
323+
EMSCRIPTEN_BINDINGS(MapInput) {
324+
register_map<string, string>("MapInput");
308325
}

lib/wiregasm/lib.cpp

Lines changed: 220 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
#include "lib.h"
2-
#include "wiregasm.h"
3-
#include <epan/conversation_table.h>
4-
#include <epan/maxmind_db.h>
52

63

74
static guint32 cum_bytes;
85
static frame_data ref_frame;
96

7+
8+
#define WG_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 */
9+
10+
struct wg_iograph
11+
{
12+
/* config */
13+
int hf_index;
14+
io_graph_item_unit_t calc_type;
15+
guint32 interval;
16+
17+
/* result */
18+
int space_items;
19+
int num_items;
20+
io_graph_item_t *items;
21+
GString *error;
22+
};
23+
1024
struct wg_conv_tap_data
1125
{
1226
const char *type;
@@ -1639,7 +1653,7 @@ wg_session_process_tap_conv_cb(void *tapdata)
16391653
*
16401654
* (m) err - error code
16411655
*/
1642-
TapResponse wg_session_process_tap(capture_file *cfile, TapInput taps)
1656+
TapResponse wg_session_process_tap(capture_file *cfile, MapInput taps)
16431657
{
16441658
TapResponse buf;
16451659
void *taps_data[16];
@@ -1785,3 +1799,205 @@ TapResponse wg_session_process_tap(capture_file *cfile, TapInput taps)
17851799
}
17861800
return buf;
17871801
}
1802+
1803+
1804+
static tap_packet_status
1805+
wg_iograph_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_, tap_flags_t flags _U_)
1806+
{
1807+
struct wg_iograph *graph = (struct wg_iograph *)g;
1808+
int idx;
1809+
bool update_succeeded;
1810+
1811+
idx = get_io_graph_index(pinfo, graph->interval);
1812+
if (idx < 0 || idx >= WG_IOGRAPH_MAX_ITEMS)
1813+
return TAP_PACKET_DONT_REDRAW;
1814+
1815+
if (idx + 1 > graph->num_items)
1816+
{
1817+
if (idx + 1 > graph->space_items)
1818+
{
1819+
int new_size = idx + 1024;
1820+
1821+
graph->items = (io_graph_item_t *)g_realloc(graph->items, sizeof(io_graph_item_t) * new_size);
1822+
reset_io_graph_items(&graph->items[graph->space_items], new_size - graph->space_items);
1823+
1824+
graph->space_items = new_size;
1825+
}
1826+
else if (graph->items == NULL)
1827+
{
1828+
graph->items = g_new(io_graph_item_t, graph->space_items);
1829+
reset_io_graph_items(graph->items, graph->space_items);
1830+
}
1831+
1832+
graph->num_items = idx + 1;
1833+
}
1834+
1835+
update_succeeded = update_io_graph_item(graph->items, idx, pinfo, edt, graph->hf_index, graph->calc_type, graph->interval);
1836+
/* XXX - TAP_PACKET_FAILED if the item couldn't be updated, with an error message? */
1837+
return update_succeeded ? TAP_PACKET_REDRAW : TAP_PACKET_DONT_REDRAW;
1838+
}
1839+
1840+
/**
1841+
* wg_session_process_iograph()
1842+
*
1843+
* Process iograph request
1844+
*
1845+
* Input:
1846+
* (o) interval - interval time in ms, if not specified: 1000ms
1847+
* (m) graph0 - First graph request
1848+
* (o) graph1...graph9 - Other graph requests
1849+
* (o) filter0 - First graph filter
1850+
* (o) filter1...filter9 - Other graph filters
1851+
*
1852+
* Graph requests can be one of: "packets", "bytes", "bits", "sum:<field>", "frames:<field>", "max:<field>", "min:<field>", "avg:<field>", "load:<field>",
1853+
* if you use variant with <field>, you need to pass field name in filter request.
1854+
*
1855+
* Output object with attributes:
1856+
* error - graph cannot be constructed
1857+
* (m) iograph - array of graph results with attributes:
1858+
* items - graph values, zeros are skipped, if value is not a number it's next index encoded as hex string
1859+
*/
1860+
IoGraphResult wg_session_process_iograph(capture_file *cfile, MapInput input)
1861+
{
1862+
IoGraphResult buf;
1863+
// interval should be an integer
1864+
const char *tok_interval = input["interval"].c_str();
1865+
struct wg_iograph graphs[10];
1866+
bool is_any_ok = false;
1867+
int graph_count;
1868+
1869+
guint32 interval_ms = 1000; /* default: one per second */
1870+
int i;
1871+
1872+
if (tok_interval)
1873+
ws_strtou32(tok_interval, NULL, &interval_ms);
1874+
1875+
for (i = graph_count = 0; i < (int)G_N_ELEMENTS(graphs); i++)
1876+
{
1877+
struct wg_iograph *graph = &graphs[graph_count];
1878+
1879+
const char *tok_graph;
1880+
const char *tok_filter;
1881+
char tok_format_buf[32];
1882+
const char *field_name;
1883+
1884+
snprintf(tok_format_buf, sizeof(tok_format_buf), "graph%d", i);
1885+
tok_graph = input[tok_format_buf].c_str();
1886+
if (!tok_graph)
1887+
break;
1888+
1889+
snprintf(tok_format_buf, sizeof(tok_format_buf), "filter%d", i);
1890+
tok_filter = input[tok_format_buf].c_str();
1891+
1892+
if (!strcmp(tok_graph, "packets"))
1893+
graph->calc_type = IOG_ITEM_UNIT_PACKETS;
1894+
else if (!strcmp(tok_graph, "bytes"))
1895+
graph->calc_type = IOG_ITEM_UNIT_BYTES;
1896+
else if (!strcmp(tok_graph, "bits"))
1897+
graph->calc_type = IOG_ITEM_UNIT_BITS;
1898+
else if (g_str_has_prefix(tok_graph, "sum:"))
1899+
graph->calc_type = IOG_ITEM_UNIT_CALC_SUM;
1900+
else if (g_str_has_prefix(tok_graph, "frames:"))
1901+
graph->calc_type = IOG_ITEM_UNIT_CALC_FRAMES;
1902+
else if (g_str_has_prefix(tok_graph, "fields:"))
1903+
graph->calc_type = IOG_ITEM_UNIT_CALC_FIELDS;
1904+
else if (g_str_has_prefix(tok_graph, "max:"))
1905+
graph->calc_type = IOG_ITEM_UNIT_CALC_MAX;
1906+
else if (g_str_has_prefix(tok_graph, "min:"))
1907+
graph->calc_type = IOG_ITEM_UNIT_CALC_MIN;
1908+
else if (g_str_has_prefix(tok_graph, "avg:"))
1909+
graph->calc_type = IOG_ITEM_UNIT_CALC_AVERAGE;
1910+
else if (g_str_has_prefix(tok_graph, "load:"))
1911+
graph->calc_type = IOG_ITEM_UNIT_CALC_LOAD;
1912+
else
1913+
break;
1914+
1915+
field_name = strchr(tok_graph, ':');
1916+
if (field_name)
1917+
field_name = field_name + 1;
1918+
1919+
graph->interval = interval_ms;
1920+
1921+
graph->hf_index = -1;
1922+
graph->error = check_field_unit(field_name, &graph->hf_index, graph->calc_type);
1923+
1924+
graph->space_items = 0; /* TODO, can avoid realloc()s in wg_iograph_packet() by calculating: capture_time / interval */
1925+
graph->num_items = 0;
1926+
graph->items = NULL;
1927+
1928+
if (!graph->error)
1929+
graph->error = register_tap_listener(
1930+
"frame",
1931+
graph,
1932+
tok_filter,
1933+
TL_REQUIRES_PROTO_TREE,
1934+
NULL,
1935+
wg_iograph_packet,
1936+
NULL,
1937+
NULL
1938+
);
1939+
1940+
graph_count++;
1941+
1942+
if (graph->error)
1943+
{
1944+
buf.error = graph->error->str;
1945+
return buf;
1946+
}
1947+
1948+
if (graph->error == NULL)
1949+
is_any_ok = true;
1950+
}
1951+
1952+
/* retap only if we have at least one ok */
1953+
if (is_any_ok)
1954+
wg_retap(cfile);
1955+
1956+
for (i = 0; i < graph_count; i++)
1957+
{
1958+
struct wg_iograph *graph = &graphs[i];
1959+
IoGraph g;
1960+
1961+
if (graph->error)
1962+
{
1963+
g_string_free(graph->error, true);
1964+
buf.error = g_strdup_printf("Error processing graph %d", i);
1965+
return buf;
1966+
}
1967+
else
1968+
{
1969+
int idx;
1970+
int next_idx = 0;
1971+
1972+
for (idx = 0; idx < graph->num_items; idx++)
1973+
{
1974+
double val;
1975+
1976+
val = get_io_graph_item(
1977+
graph->items,
1978+
graph->calc_type,
1979+
idx,
1980+
graph->hf_index,
1981+
cfile,
1982+
graph->interval,
1983+
graph->num_items
1984+
);
1985+
1986+
/* if it's zero, don't display */
1987+
if (val == 0.0)
1988+
continue;
1989+
1990+
/* cause zeros are not printed, need to output index */
1991+
if (next_idx != idx) {
1992+
g.items.push_back(idx);
1993+
}
1994+
g.items.push_back(val);
1995+
next_idx = idx + 1;
1996+
}
1997+
}
1998+
buf.iograph.push_back(g);
1999+
remove_tap_listener(graph);
2000+
g_free(graph->items);
2001+
}
2002+
return buf;
2003+
}

lib/wiregasm/lib.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <glib.h>
55
#include <epan/timestamp.h>
66
#include <wiretap/wtap.h>
7+
#include <epan/epan_dissect.h>
78
#include <epan/epan.h>
89
#include <wireshark/cfile.h>
910
#include <epan/addr_resolv.h>
@@ -15,13 +16,16 @@
1516
#include <epan/color_filters.h>
1617
#include <wsutil/filesystem.h>
1718
#include <epan/tap.h>
19+
#include <epan/conversation_table.h>
20+
#include <epan/maxmind_db.h>
21+
#include <common/io_graph_item.h>
1822
#include <common/frame_tvbuff.h>
19-
#include <epan/epan_dissect.h>
2023
#include <epan/tvbuff.h>
2124
#include <common/summary.h>
2225
#include <epan/exceptions.h>
2326
#include <epan/follow.h>
2427
#include <epan/expert.h>
28+
#include <wsutil/strtoi.h>
2529
#include "wiregasm.h"
2630

2731
// callbacks, defined in lib.js (added through --js-library)
@@ -72,7 +76,8 @@ Frame wg_process_frame(capture_file *cfile, guint32 framenum, char **err_ret);
7276
Follow wg_process_follow(capture_file *cfile, const char *follow, const char *filter, char **err_ret);
7377
bool wg_session_eo_retap_listener(capture_file *cfile, const char *tap_type, char **err_ret);
7478
DownloadResponse wg_session_process_download(capture_file *cfile, const char *token);
75-
TapResponse wg_session_process_tap(capture_file *cfile, TapInput taps);
79+
TapResponse wg_session_process_tap(capture_file *cfile, MapInput taps);
80+
IoGraphResult wg_session_process_iograph(capture_file *cfile, MapInput input);
7681
vector<CompleteField> wg_session_process_complete(const char *field);
7782
void cf_close(capture_file *cf);
7883

lib/wiregasm/wiregasm.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ Frame DissectSession::getFrame(int number)
480480
return f;
481481
}
482482

483-
TapResponse DissectSession::tap(TapInput taps)
483+
TapResponse DissectSession::tap(MapInput taps)
484484
{
485485
return wg_session_process_tap(&this->capture_file, taps);
486486
}
@@ -510,3 +510,13 @@ FilterCompletionResponse wg_complete_filter(string field)
510510
res.fields = wg_session_process_complete(field.c_str());
511511
return res;
512512
}
513+
514+
// {"graph0":"packets","filter0":"frame.number<=100"}
515+
IoGraphResult DissectSession::iograph(MapInput args)
516+
{
517+
if (args["interval"].empty())
518+
{
519+
args["interval"] = "1000";
520+
}
521+
return wg_session_process_iograph(&this->capture_file, args);
522+
}

lib/wiregasm/wiregasm.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,17 @@ struct CheckFilterResponse
104104
string error;
105105
};
106106

107+
struct IoGraph
108+
{
109+
vector<float> items;
110+
};
111+
112+
struct IoGraphResult
113+
{
114+
string error;
115+
vector<IoGraph> iograph;
116+
};
117+
107118
// base struct
108119
struct TapValue {
109120
string tap;
@@ -174,8 +185,7 @@ struct TapResponse {
174185
};
175186

176187

177-
using TapInput = std::map<string, string>;
178-
188+
using MapInput = std::map<string, string>;
179189

180190
struct PrefEnum
181191
{
@@ -271,7 +281,8 @@ class DissectSession
271281
FramesResponse getFrames(string filter, int skip, int limit);
272282
Frame getFrame(int number);
273283
Follow follow(string follow, string filter);
274-
TapResponse tap(TapInput taps);
284+
TapResponse tap(MapInput taps);
285+
IoGraphResult iograph(MapInput args);
275286
DownloadResponse download(string token);
276287
~DissectSession();
277288
};

0 commit comments

Comments
 (0)