diff --git a/lib/wiregasm/bindings.cpp b/lib/wiregasm/bindings.cpp index b7ef234..9893c67 100644 --- a/lib/wiregasm/bindings.cpp +++ b/lib/wiregasm/bindings.cpp @@ -12,6 +12,7 @@ EMSCRIPTEN_BINDINGS(Wiregasm) emscripten::function("getColumns", &wg_get_columns); emscripten::function("upload", &wg_upload_file, allow_raw_pointers()); emscripten::function("checkFilter", &wg_check_filter); + emscripten::function("completeFilter", &wg_complete_filter); emscripten::function("getUploadDirectory", &wg_get_upload_dir); emscripten::function("getPluginsDirectory", &wg_get_plugins_dir); } @@ -22,7 +23,8 @@ EMSCRIPTEN_BINDINGS(DissectSession) .constructor() .function("load", &DissectSession::load) .function("getFrames", &DissectSession::getFrames) - .function("getFrame", &DissectSession::getFrame); + .function("getFrame", &DissectSession::getFrame) + .function("follow", &DissectSession::follow); } EMSCRIPTEN_BINDINGS(ProtoTree) @@ -33,7 +35,11 @@ EMSCRIPTEN_BINDINGS(ProtoTree) .field("start", &ProtoTree::start) .field("length", &ProtoTree::length) .field("data_source_idx", &ProtoTree::data_source_idx) - .field("tree", &ProtoTree::tree); + .field("tree", &ProtoTree::tree) + .field("severity", &ProtoTree::severity) + .field("type", &ProtoTree::type) + .field("fnum", &ProtoTree::fnum) + .field("url", &ProtoTree::url); } EMSCRIPTEN_BINDINGS(DataSource) @@ -49,7 +55,8 @@ EMSCRIPTEN_BINDINGS(Frame) .field("number", &Frame::number) .field("comments", &Frame::comments) .field("data_sources", &Frame::data_sources) - .field("tree", &Frame::tree); + .field("tree", &Frame::tree) + .field("follow", &Frame::follow); } EMSCRIPTEN_BINDINGS(FrameMeta) @@ -86,6 +93,12 @@ EMSCRIPTEN_BINDINGS(CheckFilterResponse) .field("error", &CheckFilterResponse::error); } +EMSCRIPTEN_BINDINGS(FilterCompletionResponse) +{ + value_object("FilterCompletionResponse") + .field("fields", &FilterCompletionResponse::fields); +} + EMSCRIPTEN_BINDINGS(Summary) { value_object("Summary") @@ -99,10 +112,42 @@ EMSCRIPTEN_BINDINGS(Summary) .field("elapsed_time", &Summary::elapsed_time); } +EMSCRIPTEN_BINDINGS(FollowPayload) +{ + value_object("FollowPayload") + .field("number", &FollowPayload::number) + .field("data", &FollowPayload::data) + .field("server", &FollowPayload::server); +} + +EMSCRIPTEN_BINDINGS(Follow) +{ + value_object("Follow") + .field("shost", &Follow::shost) + .field("sport", &Follow::sport) + .field("sbytes", &Follow::sbytes) + .field("chost", &Follow::chost) + .field("cport", &Follow::cport) + .field("cbytes", &Follow::cbytes) + .field("payloads", &Follow::payloads); +} + +EMSCRIPTEN_BINDINGS(CompleteField) +{ + value_object("CompleteField") + .field("field", &CompleteField::field) + .field("type", &CompleteField::type) + .field("name", &CompleteField::name); +} + EMSCRIPTEN_BINDINGS(stl_wrappers) { register_vector("VectorString"); register_vector("VectorFrameMeta"); register_vector("VectorDataSource"); register_vector("VectorProtoTree"); + register_vector("VectorFollowPayload"); + register_vector("VectorCompleteField"); + // Frame::follow is a vector of vectors of strings + register_vector>("VectorVectorString"); } diff --git a/lib/wiregasm/lib.cpp b/lib/wiregasm/lib.cpp index dfbd386..11c0eba 100644 --- a/lib/wiregasm/lib.cpp +++ b/lib/wiregasm/lib.cpp @@ -4,6 +4,7 @@ static guint32 cum_bytes; static frame_data ref_frame; + void cf_close(capture_file *cf) { if (cf->state == FILE_CLOSED) @@ -313,6 +314,70 @@ int wg_load_cap_file(capture_file *cfile, summary_tally *summary) return load_cap_file(cfile, 0, 0, summary); } + +int +wg_retap(capture_file *cfile) +{ + guint32 framenum; + frame_data *fdata; + Buffer buf; + wtap_rec rec; + int err; + char *err_info = NULL; + + guint tap_flags; + gboolean create_proto_tree; + epan_dissect_t edt; + column_info *cinfo; + + /* Get the union of the flags for all tap listeners. */ + tap_flags = union_of_tap_listener_flags(); + + /* If any tap listeners require the columns, construct them. */ + cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cfile->cinfo : NULL; + + /* + * Determine whether we need to create a protocol tree. + * We do if: + * + * one of the tap listeners is going to apply a filter; + * + * one of the tap listeners requires a protocol tree. + */ + create_proto_tree = + (have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE)); + + wtap_rec_init(&rec); + ws_buffer_init(&buf, 1514); + epan_dissect_init(&edt, cfile->epan, create_proto_tree, false); + + reset_tap_listeners(); + + for (framenum = 1; framenum <= cfile->count; framenum++) { + fdata = wg_get_frame(cfile, framenum); + + if (!wtap_seek_read(cfile->provider.wth, fdata->file_off, &rec, &buf, &err, &err_info)) + break; + + fdata->ref_time = FALSE; + fdata->frame_ref_num = (framenum != 1) ? 1 : 0; + fdata->prev_dis_num = framenum - 1; + epan_dissect_run_with_taps(&edt, cfile->cd_t, &rec, + frame_tvbuff_new_buffer(&cfile->provider, fdata, &buf), + fdata, cinfo); + wtap_rec_reset(&rec); + epan_dissect_reset(&edt); + } + + wtap_rec_cleanup(&rec); + ws_buffer_free(&buf); + epan_dissect_cleanup(&edt); + draw_tap_listeners(true); + + return 0; +} + + int wg_session_process_load(capture_file *cfile, const char *path, summary_tally *summary, char **err_ret) { int ret = 0; @@ -402,10 +467,31 @@ wg_session_process_frame_cb_tree(epan_dissect_t *edt, proto_tree *tree, tvbuff_t t.start = finfo->start, t.length = finfo->length; } + if (FI_GET_FLAG(finfo, PI_SEVERITY_MASK)) { + t.severity = try_val_to_str(FI_GET_FLAG(finfo, PI_SEVERITY_MASK), expert_severity_vals); + } + if (finfo->hfinfo) { char *filter; + if (finfo->hfinfo->type == FT_PROTOCOL) + { + t.type = "proto"; + } + else if (finfo->hfinfo->type == FT_FRAMENUM) + { + t.type = "framenum"; + t.fnum = static_cast(finfo->value.value.uinteger); + } + else if (FI_GET_FLAG(finfo, FI_URL) && finfo->hfinfo->type == FT_STRING) + { + char *url = fvalue_to_string_repr(NULL, &finfo->value, FTREPR_DISPLAY, finfo->hfinfo->display); + t.type = "url"; + t.url = url; + wmem_free(NULL, url); + } + filter = proto_construct_match_selected_string(finfo, edt); if (filter) { @@ -427,32 +513,57 @@ wg_session_process_frame_cb_tree(epan_dissect_t *edt, proto_tree *tree, tvbuff_t return res; } + +struct VisitData { + packet_info *pi; + vector> *followArray; +}; + +static gboolean +wg_session_follower_visit_cb(const void *key _U_, void *value, void *user_data) { + register_follow_t *follower = (register_follow_t *) value; + VisitData *visitData = (VisitData *) user_data; + packet_info *pi = visitData->pi; + vector> *followArray = visitData->followArray; + + const int proto_id = get_follow_proto_id(follower); + guint32 ignore_stream; + guint32 ignore_sub_stream; + + if (proto_is_frame_protocol(pi->layers, proto_get_protocol_filter_name(proto_id))) + { + const char *layer_proto = proto_get_protocol_short_name(find_protocol_by_id(proto_id)); + char *follow_filter; + + follow_filter = get_follow_conv_func(follower)(NULL, pi, &ignore_stream, &ignore_sub_stream); + // [['HTTP', 'tcp.stream eq 0'],['TCP', 'tcp.stream eq 0']] + vector follow; + follow.push_back(static_cast(layer_proto)); + follow.push_back(static_cast(follow_filter)); + followArray->push_back(follow); + g_free(follow_filter); + } + return false; +} + void wg_session_process_frame_cb(capture_file *cfile, epan_dissect_t *edt, proto_tree *tree, struct epan_column_info *cinfo, const GSList *data_src, void *data) { packet_info *pi = &edt->pi; frame_data *fdata = pi->fd; - wtap_block_t pkt_block = NULL; + wtap_block_t pkt_block = fdata->has_modified_block ? cap_file_provider_get_modified_block(&cfile->provider, fdata) : pi->rec->block; Frame *f = (Frame *)data; - if (fdata->has_modified_block) - pkt_block = cap_file_provider_get_modified_block(&cfile->provider, fdata); - else - pkt_block = pi->rec->block; - if (pkt_block) { - guint i; - guint n; - gchar *comment; + guint n = wtap_block_count_option(pkt_block, OPT_COMMENT); - n = wtap_block_count_option(pkt_block, OPT_COMMENT); - - for (i = 0; i < n; i++) + for (guint i = 0; i < n; i++) { + gchar *comment; if (WTAP_OPTTYPE_SUCCESS == wtap_block_get_nth_string_option_value(pkt_block, OPT_COMMENT, i, &comment)) { - f->comments.push_back(string(comment)); + f->comments.push_back(std::string(comment)); } } } @@ -465,11 +576,9 @@ void wg_session_process_frame_cb(capture_file *cfile, epan_dissect_t *edt, proto if (data_src && data_src->next /* only needed if there are more than one data source */) { guint count = g_slist_length((GSList *)data_src); - guint i; - tvbs = (tvbuff_t **)g_malloc0((count + 1) * sizeof(*tvbs)); - for (i = 0; i < count; i++) + for (guint i = 0; i < count; i++) { const struct data_source *src = (const struct data_source *)g_slist_nth_data((GSList *)data_src, i); @@ -504,8 +613,86 @@ void wg_session_process_frame_cb(capture_file *cfile, epan_dissect_t *edt, proto data_src = data_src->next; } + + VisitData visitData; + visitData.pi = pi; + vector> followArray; // Initialize the followArray vector + visitData.followArray = &followArray; // Assign the address of followArray to visitData.followArray + follow_iterate_followers(wg_session_follower_visit_cb, &visitData); + // Assign followArray to f->follow + for (const auto& follow : *visitData.followArray) { + f->follow.push_back(follow); + } } +Follow wg_session_process_follow(capture_file *cfile, const char* tok_follow, const char* tok_filter, char **err_ret) +{ + register_follow_t *follower; + GString *tap_error; + + follow_info_t *follow_info; + + const char *host; + char *port; + Follow f; + + follower = get_follow_by_name(tok_follow); + if (!follower) + { + *err_ret = g_strdup_printf("follower=%s not found", tok_follow); + return f; + } + + /* follow_reset_stream ? */ + follow_info = g_new0(follow_info_t, 1); + /* gui_data, filter_out_filter not set, but not used by dissector */ + + tap_error = register_tap_listener(get_follow_tap_string(follower), follow_info, tok_filter, 0, NULL, get_follow_tap_handler(follower), NULL, NULL); + if (tap_error) + { + *err_ret = g_strdup_printf("name=%s error=%s", tok_follow, tap_error->str); + g_string_free(tap_error, TRUE); + g_free(follow_info); + return f; + } + + wg_retap(cfile); + /* Server information: hostname, port, bytes sent */ + host = address_to_name(&follow_info->server_ip); + f.shost = host; + + port = get_follow_port_to_display(follower)(NULL, follow_info->server_port); + f.sport = port; + wmem_free(NULL, port); + f.sbytes = follow_info->bytes_written[0]; + + /* Client information: hostname, port, bytes sent */ + host = address_to_name(&follow_info->client_ip); + f.chost = host; + + port = get_follow_port_to_display(follower)(NULL, follow_info->client_port); + f.cport = port; + wmem_free(NULL, port); + f.cbytes = follow_info->bytes_written[1]; + + if (follow_info->payload) + { + follow_record_t *follow_record; + GList *cur; + for (cur = g_list_last(follow_info->payload); cur; cur = g_list_previous(cur)) + { + follow_record = (follow_record_t *) cur->data; + char *encoded = g_base64_encode(follow_record->data->data, follow_record->data->len); + f.payloads.push_back(FollowPayload{int(follow_record->packet_num), string(encoded), static_cast(follow_record->is_server ? 1 : 0)}); + } + } + + remove_tap_listener(follow_info); + follow_info_free(follow_info); + return f; +} + + void wg_session_process_frames_cb(capture_file *cfile, epan_dissect_t *edt, proto_tree *tree _U_, struct epan_column_info *cinfo, const GSList *data_src _U_, void *data) { @@ -876,4 +1063,82 @@ FramesResponse wg_process_frames(capture_file *cfile, GHashTable *filter_table, result.frames = res; return result; -} \ No newline at end of file +} + +Follow wg_process_follow(capture_file *cfile, const char* follow, const char* filter, char **err_ret) +{ + Follow fdata = wg_session_process_follow(cfile, follow, filter, err_ret); + return fdata; +} + +/** + * Process complete request + * + * Input: + * field - field to be completed + * + * Output object with : + * err - always 0attributes + * field - array of object with attributes: + * field - field text + * type - field type (FT_ number) + * name - field name + */ +vector +wg_session_process_complete(const char *tok_field) +{ + vector res; + if (tok_field != NULL && tok_field[0]) + { + const size_t filter_length = strlen(tok_field); + const int filter_with_dot = !!strchr(tok_field, '.'); + + void *proto_cookie; + void *field_cookie; + int proto_id; + + for (proto_id = proto_get_first_protocol(&proto_cookie); proto_id != -1; proto_id = proto_get_next_protocol(&proto_cookie)) + { + protocol_t *protocol = find_protocol_by_id(proto_id); + const char *protocol_filter; + const char *protocol_name; + header_field_info *hfinfo; + + if (!proto_is_protocol_enabled(protocol)) + continue; + + protocol_name = proto_get_protocol_long_name(protocol); + protocol_filter = proto_get_protocol_filter_name(proto_id); + + if (strlen(protocol_filter) >= filter_length && !g_ascii_strncasecmp(tok_field, protocol_filter, filter_length)) + { + res.push_back(CompleteField{string(protocol_filter), static_cast(FT_PROTOCOL), string(protocol_name)}); + } + + if (!filter_with_dot) + continue; + + for (hfinfo = proto_get_first_protocol_field(proto_id, &field_cookie); hfinfo != NULL; hfinfo = proto_get_next_protocol_field(proto_id, &field_cookie)) + { + if (hfinfo->same_name_prev_id != -1) /* ignore duplicate names */ + continue; + + if (strlen(hfinfo->abbrev) >= filter_length && !g_ascii_strncasecmp(tok_field, hfinfo->abbrev, filter_length)) + { + CompleteField f; + { + f.field = string(hfinfo->abbrev); + /* XXX, skip displaying name, if there are multiple (to not confuse user) */ + if (hfinfo->same_name_next == NULL) + { + f.type = static_cast(hfinfo->type); + f.name = string(hfinfo->name); + } + } + res.push_back(f); + } + } + } + } + return res; +} diff --git a/lib/wiregasm/lib.h b/lib/wiregasm/lib.h index 0d58e7f..f935f98 100644 --- a/lib/wiregasm/lib.h +++ b/lib/wiregasm/lib.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include "wiregasm.h" // callbacks, defined in lib.js (added through --js-library) @@ -66,6 +68,8 @@ void wg_session_filter_free(gpointer data); int wg_session_process_load(capture_file *cfile, const char *path, summary_tally *summary, char **err_ret); FramesResponse wg_process_frames(capture_file *cfile, GHashTable *filter_table, const char *filter, guint32 skip, guint32 limit, char **err_ret); Frame wg_process_frame(capture_file *cfile, guint32 framenum, char **err_ret); +Follow wg_process_follow(capture_file *cfile, const char* follow, const char* filter, char **err_ret); +vector wg_session_process_complete(const char* field); void cf_close(capture_file *cf); -#endif \ No newline at end of file +#endif diff --git a/lib/wiregasm/meson.build b/lib/wiregasm/meson.build index 414e1e4..66f4c3e 100644 --- a/lib/wiregasm/meson.build +++ b/lib/wiregasm/meson.build @@ -45,7 +45,7 @@ link_args = [ # XXX: drastically increases binary size, maybe selectively asyncify functions? # '-s', 'ASYNCIFY=1', - + # XXX: loaded files can be big '-s', 'ALLOW_MEMORY_GROWTH=1', @@ -105,4 +105,4 @@ foreach tgt: [ 'wiregasm.wasm', 'wiregasm.data' ] install: true, install_dir: get_option('bindir'), ) -endforeach \ No newline at end of file +endforeach diff --git a/lib/wiregasm/wiregasm.cpp b/lib/wiregasm/wiregasm.cpp index 8502332..390a15e 100644 --- a/lib/wiregasm/wiregasm.cpp +++ b/lib/wiregasm/wiregasm.cpp @@ -66,7 +66,7 @@ bool wg_reload_lua_plugins() if (!wg_initialized) { return false; } - + wslua_reload_plugins(NULL, NULL); on_status(INFO, "Reload complete!"); @@ -199,6 +199,20 @@ LoadResponse DissectSession::load() return r; } +Follow DissectSession::follow(string follow, string filter) +{ + char *err_ret = NULL; + Follow ret = wg_process_follow(&this->capture_file, follow.c_str(), filter.c_str(), &err_ret); + + // XXX: propagate? + if (err_ret) + { + g_free(err_ret); + } + + return ret; +} + FramesResponse DissectSession::getFrames(string filter, int skip, int limit) { char *err_ret = NULL; @@ -240,3 +254,10 @@ DissectSession::~DissectSession() col_cleanup(&this->capture_file.cinfo); cf_close(&this->capture_file); } + +FilterCompletionResponse wg_complete_filter(string field) +{ + FilterCompletionResponse res; + res.fields = wg_session_process_complete(field.c_str()); + return res; +} diff --git a/lib/wiregasm/wiregasm.h b/lib/wiregasm/wiregasm.h index d9dd8fd..691525d 100644 --- a/lib/wiregasm/wiregasm.h +++ b/lib/wiregasm/wiregasm.h @@ -8,28 +8,57 @@ using namespace std; + struct ProtoTree { string label; string filter; + string severity; + string type; + string url; + unsigned int fnum; int start; int length; int data_source_idx; vector tree; }; +struct FollowPayload { + int number; + string data; + unsigned int server; +}; + +struct Follow +{ + string shost; + string sport; + unsigned int sbytes; + string chost; + string cport; + unsigned int cbytes; + vector payloads; +}; + struct DataSource { string name; string data; }; +struct CompleteField { + string field; + int type; + string name; +}; + struct Frame { int number; vector comments; vector data_sources; vector tree; + vector> follow; }; struct FrameMeta @@ -74,6 +103,11 @@ struct CheckFilterResponse string error; }; +struct FilterCompletionResponse +{ + vector fields; +}; + // globals bool wg_init(); @@ -82,6 +116,7 @@ void wg_destroy(); string wg_upload_file(string name, int buffer_ptr, size_t size); vector wg_get_columns(); CheckFilterResponse wg_check_filter(string filter); +FilterCompletionResponse wg_complete_filter(string field); string wg_get_upload_dir(); string wg_get_plugins_dir(); @@ -97,7 +132,8 @@ class DissectSession LoadResponse load(); FramesResponse getFrames(string filter, int skip, int limit); Frame getFrame(int number); + Follow follow(string follow, string filter); ~DissectSession(); }; -#endif \ No newline at end of file +#endif diff --git a/package-lock.json b/package-lock.json index fedc361..414ff2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@goodtools/wiregasm", - "version": "1.1.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@goodtools/wiregasm", - "version": "1.1.0", + "version": "1.3.0", "license": "GPLV2", "devDependencies": { "@parcel/packager-ts": "^2.8.2", diff --git a/src/index.test.ts b/src/index.test.ts index bdfad9d..3f88d56 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,6 +1,8 @@ +import * as fs from "fs/promises"; + import { Wiregasm, WiregasmLib, WiregasmLibOverrides } from "."; + import loadWiregasm from "../built/bin/wiregasm.js"; -import * as fs from "fs/promises"; import pako from "pako"; // overrides need to be copied over to every instance @@ -12,11 +14,11 @@ const buildTestOverrides = (): WiregasmLibOverrides => { }, // supress all unwanted logs in test-suite // eslint-disable-next-line @typescript-eslint/no-empty-function - printErr: () => {}, + printErr: () => { }, // eslint-disable-next-line @typescript-eslint/no-empty-function - print: () => {}, + print: () => { }, // eslint-disable-next-line @typescript-eslint/no-empty-function - handleStatus: () => {}, + handleStatus: () => { }, }; }; @@ -120,15 +122,48 @@ describe("Wiregasm Library Wrapper", () => { expect(frames.frames.size()).toEqual(4); const frame = wg.frame(1); - expect(frame.number).toEqual(1); expect(frame.data_sources.size()).toBeGreaterThan(0); + expect(frame.follow.size()).toBe(1); + expect(frame.follow.get(0).get(0)).toBe("UDP"); + expect(frame.follow.get(0).get(1)).toBe("udp.stream eq 0"); }); test("filter validation works", async () => { expect(wg.test_filter("tcp").ok).toBeTruthy(); expect(wg.test_filter("txx").ok).toBeFalsy(); }); + + test("follow works", async () => { + const data = await fs.readFile("samples/dhcp.pcap"); + const ret = wg.load("dhcp.pcap", data); + expect(ret.code).toEqual(0); + + const frame = wg.frame(1); + const follow = wg.follow( + frame.follow.get(0).get(0), + frame.follow.get(0).get(1) + ); + expect(typeof follow.shost == "string").toBeTruthy(); + expect(typeof follow.sbytes == "number").toBeTruthy(); + expect(typeof follow.sport == "string").toBeTruthy(); + expect(typeof follow.cport == "string").toBeTruthy(); + expect(typeof follow.chost == "string").toBeTruthy(); + expect(typeof follow.cbytes == "number").toBeTruthy(); + expect(follow.payloads.size()).toBeGreaterThan(0); + }); + + test("filter compilation works", async () => { + expect(wg.complete_filter("tcp").fields.length).toBeGreaterThan(0); + expect(wg.complete_filter("tcp").fields.find( + (f) => f.field === "tcp" + )).toEqual({ + field: "tcp", + name: "Transmission Control Protocol", + type: 1, + }); + expect(wg.complete_filter("txx").fields.length).toBe(0); + }) }); const buildCompressedOverrides = async (): Promise => { @@ -144,11 +179,11 @@ const buildCompressedOverrides = async (): Promise => { }, // eslint-disable-next-line @typescript-eslint/no-empty-function - printErr: () => {}, + printErr: () => { }, // eslint-disable-next-line @typescript-eslint/no-empty-function - print: () => {}, + print: () => { }, // eslint-disable-next-line @typescript-eslint/no-empty-function - handleStatus: () => {}, + handleStatus: () => { }, }; }; diff --git a/src/index.ts b/src/index.ts index 5d11a6c..b2a5f23 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,17 @@ import { + BeforeInitCallback, CheckFilterResponse, + CompleteField, DissectSession, + Follow, Frame, FramesResponse, LoadResponse, WiregasmLib, WiregasmLibOverrides, WiregasmLoader, - BeforeInitCallback, } from "./types"; + import { vectorToArray } from "./utils"; /** @@ -62,6 +65,14 @@ export class Wiregasm { return this.lib.checkFilter(filter); } + complete_filter(filter: string): { err: string; fields: CompleteField[] } { + const out = this.lib.completeFilter(filter); + return { + err: out.err, + fields: vectorToArray(out.fields), + }; + } + reload_lua_plugins() { this.lib.reloadLuaPlugins(); } @@ -113,6 +124,10 @@ export class Wiregasm { return this.session.getFrame(num); } + follow(follow: string, filter: string): Follow { + return this.session.follow(follow, filter); + } + destroy() { if (this.initialized) { if (this.session !== null) { diff --git a/src/types.ts b/src/types.ts index b081478..540b402 100644 --- a/src/types.ts +++ b/src/types.ts @@ -35,6 +35,9 @@ export interface ProtoTree { start: number; length: number; data_source_idx: number; + type: "proto" | "url" | "framenum" | ""; + url?: string; + fnum?: number; tree: Vector; } @@ -43,13 +46,37 @@ export interface Frame { comments: Vector; data_sources: Vector; tree: Vector; + follow: Vector> } +export interface CompleteField { + field: string; + type: string; + name: string; +} + + export interface FramesResponse { frames: Vector; matched: number; } +export interface FollowPayload { + number: number; + server: number; + data: string; +} + +export interface Follow { + shost: string; + sport: string; + sbytes: number; + chost: string; + cport: string; + cbytes: number; + payloads: Vector; +} + export interface FrameMeta { number: number; comments: boolean; @@ -105,10 +132,12 @@ export interface DissectSession { * @param number Frame number */ getFrame(number: number): Frame; + + follow(follow: string, filter: string): Follow; } export interface DissectSessionConstructable { - new (path: string): DissectSession; + new(path: string): DissectSession; } export interface CheckFilterResponse { @@ -210,6 +239,7 @@ export interface WiregasmLib extends EmscriptenModule { */ checkFilter(filter: string): CheckFilterResponse; + completeFilter(filter: string): { err: string; fields: Vector }; /** * Returns the column headers */