From a86c5f7cae7ec9a3398300555a0b644689d946a1 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 19 Sep 2024 06:14:53 +0200 Subject: Merging upstream version 4.4.0. Signed-off-by: Daniel Baumann --- epan/dissectors/packet-nmf.c | 697 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 697 insertions(+) create mode 100644 epan/dissectors/packet-nmf.c (limited to 'epan/dissectors/packet-nmf.c') diff --git a/epan/dissectors/packet-nmf.c b/epan/dissectors/packet-nmf.c new file mode 100644 index 00000000..d78de0e9 --- /dev/null +++ b/epan/dissectors/packet-nmf.c @@ -0,0 +1,697 @@ +/* + * packet-nmf.c + * + * Routines for [MC-NMF] .NET Message Framing Protocol + * + * Copyright 2017 Stefan Metzmacher + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include "packet-tcp.h" +#include "packet-windows-common.h" +#include "packet-gssapi.h" + +#define NMF_PORT 9389 + +void proto_register_nmf(void); +void proto_reg_handoff_nmf(void); + +static dissector_handle_t gssapi_handle; +static dissector_handle_t gssapi_wrap_handle; + +static dissector_handle_t xml_handle; + +static int proto_nmf; + +static int ett_nmf; +static int ett_nmf_payload; + +static int hf_nmf_record; +static int hf_nmf_record_type; +static int hf_nmf_version_major; +static int hf_nmf_version_minor; +static int hf_nmf_mode_value; +static int hf_nmf_via_length; +static int hf_nmf_via_value; +static int hf_nmf_known_mode_value; +static int hf_nmf_sized_envelope_length; +static int hf_nmf_upgrade_length; +static int hf_nmf_upgrade_protocol; +static int hf_nmf_negotiate_type; +static int hf_nmf_negotiate_length; +static int hf_nmf_protect_length; + +static expert_field ei_nmf_bad_record_size; + +static bool nmf_reassemble = true; + +enum nmf_record_type { + NMF_VERSION_RECORD = 0x00, + NMF_MODE_RECORD = 0x01, + NMF_VIA_RECORD = 0x02, + NMF_KNOWN_ENCODING_RECORD = 0x03, + NMF_EXTENSIBLE_ENCODING_RECORD = 0x04, + NMF_UNSIZED_ENVELOPE_RECORD = 0x05, + NMF_SIZED_ENVELOPE_RECORD = 0x06, + NMF_END_RECORD = 0x07, + NMF_FAULT_RECORD = 0x08, + NMF_UPGRADE_REQUEST_RECORD = 0x09, + NMF_UPGRADE_RESPONSE_RECORD = 0x0A, + NMF_PREAMBLE_ACK_RECORD = 0x0B, + NMF_PREAMBLE_END_RECORD = 0x0C +}; + +static const value_string record_types[] = { + { NMF_VERSION_RECORD, "Version Record"}, + { NMF_MODE_RECORD, "Mode Record"}, + { NMF_VIA_RECORD, "Via Record"}, + { NMF_KNOWN_ENCODING_RECORD, "Known Encoding Record"}, + { NMF_EXTENSIBLE_ENCODING_RECORD, "Extensible Encoding Record"}, + { NMF_UNSIZED_ENVELOPE_RECORD, "Unsized Envelope Record"}, + { NMF_SIZED_ENVELOPE_RECORD, "Sized Envelope Record"}, + { NMF_END_RECORD, "End Record"}, + { NMF_FAULT_RECORD, "Fault Record"}, + { NMF_UPGRADE_REQUEST_RECORD, "Upgrade Request Record"}, + { NMF_UPGRADE_RESPONSE_RECORD, "Upgrade Response Record"}, + { NMF_PREAMBLE_ACK_RECORD, "Preamble Ack Record"}, + { NMF_PREAMBLE_END_RECORD, "Preamble End Record"}, + { 0, NULL } +}; + +static const value_string mode_values[] = { + { 0x01, "Singleton-Unsized"}, + { 0x02, "Duplex"}, + { 0x03, "Simplex"}, + { 0, NULL } +}; + +static const value_string known_mode_values[] = { + { 0x00, "SOAP 1.1 UTF-8"}, + { 0x01, "SOAP 1.1 UTF-16"}, + { 0x02, "SOAP 1.1 Unicode Little-Endian"}, + { 0x03, "SOAP 1.2 UTF-8"}, + { 0x04, "SOAP 1.2 UTF-16"}, + { 0x05, "SOAP 1.2 Unicode Little-Endian"}, + { 0x06, "SOAP 1.2 MOTM"}, + { 0x07, "SOAP 1.2 Binary"}, + { 0x08, "SOAP 1.2 Binary with in-band dictionary"}, + { 0, NULL } +}; + +typedef struct nmf_conv_info_t { + uint32_t fnum_upgraded; + uint32_t fnum_negotiated; +} nmf_conv_info_t; + +/* Read the the varint holding the record size. + * Callers MUST check for a 0 return value, which indicates that + * parsing the varint failed, to avoid infinite loops. + */ +static int +dissect_nmf_record_size(tvbuff_t *tvb, proto_tree *tree, + int hf_index, int offset, uint32_t *_size) +{ + uint64_t size = 0; + int start_offset = offset; + + /* 5 is the encoded size for UINT32_MAX (but can also contain larger + * varints). + */ + unsigned len = tvb_get_varint(tvb, offset, 5, &size, ENC_VARINT_PROTOBUF); + if (len == 0) { + proto_tree_add_expert_format(tree, NULL, &ei_nmf_bad_record_size, tvb, offset, 5, + "Invalid record size; varint does not end in five bytes"); + return 0; + } + if (size > UINT32_MAX) { + proto_tree_add_expert_format(tree, NULL, &ei_nmf_bad_record_size, tvb, offset, len, + "Invalid record size %" PRIu64, size); + return 0; + } + + if (_size != NULL) { + *_size = (uint32_t)size; + } + + if (tree != NULL && hf_index != -1) { + proto_item *item = NULL; + item = proto_tree_add_item(tree, hf_index, tvb, + start_offset, -1, ENC_NA); + proto_item_set_len(item, (int)len); + proto_item_append_text(item, ": %u (0x%x)", + (unsigned)size, (unsigned)size); + } + + return offset; +} + +static int +dissect_nmf_record(tvbuff_t *tvb, packet_info *pinfo, + nmf_conv_info_t *nmf_info, + proto_tree *tree, int offset) +{ + proto_item *record_item = NULL; + proto_tree *record_tree = NULL; + const char *record_name = NULL; + enum nmf_record_type record_type; + uint32_t size = 0; + const uint8_t *str = NULL; + tvbuff_t *payload_tvb = NULL; + tvbuff_t *xml_tvb = NULL; + + record_item = proto_tree_add_item(tree, hf_nmf_record, tvb, offset, -1, ENC_NA); + proto_item_append_text(record_item, ", start_offset=0x%x, ", (unsigned)offset); + record_tree = proto_item_add_subtree(record_item, ett_nmf); + + record_type = (enum nmf_record_type)tvb_get_uint8(tvb, offset); + record_name = val_to_str_const((uint32_t)record_type, record_types, + "Unknown Record"); + proto_tree_add_item(record_tree, hf_nmf_record_type, + tvb, offset, 1, ENC_NA); + offset += 1; + + col_append_str(pinfo->cinfo, COL_INFO, record_name); + proto_item_append_text(record_item, "%s", record_name); + + switch (record_type) { + case NMF_VERSION_RECORD: + proto_tree_add_item(record_tree, hf_nmf_version_major, + tvb, offset, 1, ENC_NA); + offset += 1; + proto_tree_add_item(record_tree, hf_nmf_version_minor, + tvb, offset, 1, ENC_NA); + offset += 1; + break; + case NMF_MODE_RECORD: + proto_tree_add_item(record_tree, hf_nmf_mode_value, + tvb, offset, 1, ENC_NA); + offset += 1; + break; + case NMF_VIA_RECORD: + offset = dissect_nmf_record_size(tvb, record_tree, + hf_nmf_via_length, + offset, &size); + if (offset <= 0) { + return -1; + } + + proto_tree_add_item_ret_string(record_tree, hf_nmf_via_value, + tvb, offset, size, ENC_UTF_8, + wmem_packet_scope(), &str); + offset += size; + proto_item_append_text(record_item, ": %s", (const char *)str); + break; + case NMF_KNOWN_ENCODING_RECORD: + proto_tree_add_item(record_tree, hf_nmf_known_mode_value, + tvb, offset, 1, ENC_NA); + offset += 1; + break; + case NMF_EXTENSIBLE_ENCODING_RECORD: + /* TODO */ + break; + case NMF_UNSIZED_ENVELOPE_RECORD: + /* TODO */ + break; + case NMF_SIZED_ENVELOPE_RECORD: + offset = dissect_nmf_record_size(tvb, record_tree, + hf_nmf_sized_envelope_length, + offset, &size); + if (offset <= 0) { + return -1; + } + + payload_tvb = tvb_new_subset_length(tvb, offset, size); + offset += size; + proto_item_append_text(record_item, ": Payload (%u byte%s)", + size, plurality(size, "", "s")); + proto_tree_add_format_text(record_tree, payload_tvb, 0, size); +#if 0 + if (0) { + /* TODO: + * + * 1. reassemble payload + * 2. use + * [MC-NBFSE] .NET Binary Format: SOAP Extension + * [MC-NBFS] .NET Binary Format: SOAP Data Structure + * [MC-NBFX] .NET Binary Format: XML Data Structure + * to generate XML + * 3. call the XML dissector. + */ + if (payload_tvb != NULL) { + xml_tvb = NULL; + } + } +#endif + if (xml_tvb != NULL) { + call_dissector_with_data(xml_handle, xml_tvb, pinfo, + record_tree, NULL); + } + break; + case NMF_END_RECORD: + /* TODO */ + break; + case NMF_FAULT_RECORD: + /* TODO */ + break; + case NMF_UPGRADE_REQUEST_RECORD: + offset = dissect_nmf_record_size(tvb, record_tree, + hf_nmf_upgrade_length, + offset, &size); + if (offset <= 0) { + return -1; + } + + proto_tree_add_item_ret_string(record_tree, hf_nmf_upgrade_protocol, + tvb, offset, size, ENC_UTF_8, + wmem_packet_scope(), &str); + offset += size; + proto_item_append_text(record_item, ": %s", (const char *)str); + break; + + case NMF_UPGRADE_RESPONSE_RECORD: + nmf_info->fnum_upgraded = pinfo->fd->num; + break; + case NMF_PREAMBLE_ACK_RECORD: + /* TODO */ + break; + case NMF_PREAMBLE_END_RECORD: + /* TODO */ + break; + } + + proto_item_append_text(record_item, ", end_offset=0x%x", (unsigned)offset); + proto_item_set_end(record_item, tvb, offset); + + return offset; +} + +static unsigned +nmf_get_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *_info) +{ + nmf_conv_info_t *nmf_info = (nmf_conv_info_t *)_info; + enum nmf_record_type record_type; + int start_offset = offset; + + if (pinfo->fd->num > nmf_info->fnum_negotiated) { + unsigned remaining = tvb_captured_length_remaining(tvb, offset); + unsigned len = 0; + unsigned needed = 0; + + if (remaining < 4) { + return 0; + } + + len = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN); + offset += 4; + + needed = 4 + len; + return needed; + } + + if (pinfo->fd->num > nmf_info->fnum_upgraded) { + unsigned remaining = tvb_captured_length_remaining(tvb, offset); + unsigned len = 0; + unsigned needed = 0; + + if (remaining < 5) { + return 0; + } + + offset += 3; + + len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN); + offset += 2; + + needed = 5 + len; + return needed; + } + + record_type = (enum nmf_record_type)tvb_get_uint8(tvb, offset); + offset += 1; + + switch (record_type) { + case NMF_VIA_RECORD: + case NMF_SIZED_ENVELOPE_RECORD: + case NMF_UPGRADE_REQUEST_RECORD: + { + /* Variable sized record. We must not throw an exception. */ + uint64_t size = 0; + unsigned len = tvb_get_varint(tvb, offset, + tvb_captured_length_remaining(tvb, offset), + &size, ENC_VARINT_PROTOBUF); + /* [MC-NMF] 2.2.2 The record length can be up to UINT32_MAX, + * with an encoded size of 5 bytes. + */ + if (len == 0) { + /* Parsing failed. */ + if (tvb_captured_length_remaining(tvb, offset) < 5) { + /* Fewer than five bytes, so ask for one more segment. */ + return 0; + } + + /* We had at least 5 bytes, so the length is invalid. + * Just take the rest of this segment. + * The expert info will be handled in the main dissection + * routine. */ + return tvb_reported_length_remaining(tvb, start_offset); + } + if (size > UINT32_MAX) { + /* Invalid length */ + return tvb_reported_length_remaining(tvb, start_offset); + } + offset += (int)len; + offset += (int)size; + break; + } + case NMF_VERSION_RECORD: + offset += 2; + break; + case NMF_MODE_RECORD: + offset += 1; + break; + case NMF_KNOWN_ENCODING_RECORD: + offset += 1; + break; + case NMF_EXTENSIBLE_ENCODING_RECORD: + /* TODO */ + break; + case NMF_UNSIZED_ENVELOPE_RECORD: + /* TODO */ + break; + case NMF_END_RECORD: + /* TODO */ + break; + case NMF_FAULT_RECORD: + /* TODO */ + break; + case NMF_UPGRADE_RESPONSE_RECORD: + break; + case NMF_PREAMBLE_ACK_RECORD: + /* TODO */ + break; + case NMF_PREAMBLE_END_RECORD: + /* TODO */ + break; + } + + return offset - start_offset; +} + +static int +dissect_nmf_payload(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, nmf_conv_info_t *nmf_info) +{ + int offset = 0; + + while (tvb_reported_length_remaining(tvb, offset) > 0) { + int ret; + + ret = dissect_nmf_record(tvb, pinfo, nmf_info, tree, offset); + if (ret <= 0) { + return -1; + } + offset += ret; + } + + return offset; +} + +static int +dissect_nmf_pdu(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, void *_info) +{ + nmf_conv_info_t *nmf_info = (nmf_conv_info_t *)_info; + + pinfo->fragmented = true; + + if (pinfo->fd->num > nmf_info->fnum_negotiated) { + proto_item *item = proto_tree_get_parent(tree); + uint32_t len = 0; + int offset = 0; + tvbuff_t *gssapi_tvb = NULL; + tvbuff_t *plain_tvb = NULL, *decr_tvb= NULL; + int ver_len; + gssapi_encrypt_info_t gssapi_encrypt; + + len = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN); + proto_tree_add_item(tree, hf_nmf_negotiate_length, + tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + col_set_str(pinfo->cinfo, COL_INFO, "NMF GSSAPI"); + col_add_fstr(pinfo->cinfo, COL_INFO, + "Protected Packet len: %u (0x%x)", + (unsigned)len, (unsigned)len); + proto_item_append_text(item, ", Protected Packet len: %u (0x%x)", + (unsigned)len, (unsigned)len); + + gssapi_tvb = tvb_new_subset_length(tvb, offset, len); + offset += len; + + /* Attempt decryption of the GSSAPI wrapped data if possible */ + memset(&gssapi_encrypt, 0, sizeof(gssapi_encrypt)); + gssapi_encrypt.decrypt_gssapi_tvb=DECRYPT_GSSAPI_NORMAL; + + ver_len = call_dissector_with_data(gssapi_wrap_handle, gssapi_tvb, + pinfo, tree, &gssapi_encrypt); + /* if we could unwrap, do a tvb shuffle */ + if (gssapi_encrypt.gssapi_decrypted_tvb) { + decr_tvb=gssapi_encrypt.gssapi_decrypted_tvb; + } else if (gssapi_encrypt.gssapi_wrap_tvb) { + plain_tvb=gssapi_encrypt.gssapi_wrap_tvb; + } + + /* + * if we don't have unwrapped data, + * see if the wrapping involved encryption of the + * data; if not, just use the plaintext data. + */ + if (!decr_tvb && !plain_tvb) { + if(!gssapi_encrypt.gssapi_data_encrypted){ + plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len); + } + } + + if (decr_tvb) { + proto_tree *enc_tree = NULL; + unsigned decr_len = tvb_reported_length(decr_tvb); + + col_set_str(pinfo->cinfo, COL_INFO, "NMF GSS-API Privacy (decrypted): "); + + if (tree) { + enc_tree = proto_tree_add_subtree_format(tree, decr_tvb, 0, -1, + ett_nmf_payload, NULL, + "GSS-API Encrypted payload (%d byte%s)", + decr_len, + plurality(decr_len, "", "s")); + } + dissect_nmf_payload(decr_tvb, pinfo, enc_tree, nmf_info); + } else if (plain_tvb) { + proto_tree *plain_tree = NULL; + unsigned plain_len = tvb_reported_length(plain_tvb); + + col_set_str(pinfo->cinfo, COL_INFO, "NMF GSS-API Integrity: "); + + if (tree) { + plain_tree = proto_tree_add_subtree_format(tree, plain_tvb, 0, -1, + ett_nmf_payload, NULL, + "GSS-API payload (%d byte%s)", + plain_len, + plurality(plain_len, "", "s")); + } + + dissect_nmf_payload(plain_tvb, pinfo, plain_tree, nmf_info); + } else { + col_add_fstr(pinfo->cinfo, COL_INFO, "NMF GSS-API Privacy: payload (%d byte%s)", + len, plurality(len, "", "s")); + + proto_tree_add_format_text(tree, gssapi_tvb, 0, len); + } + return offset; + } + + if (pinfo->fd->num > nmf_info->fnum_upgraded) { + proto_item *item = proto_tree_get_parent(tree); + unsigned rlen = tvb_reported_length(tvb); + uint16_t len = 0; + uint8_t type; + int offset = 0; + tvbuff_t *negotiate_tvb = NULL; + + col_set_str(pinfo->cinfo, COL_INFO, "NMF Upgrade"); + + type = tvb_get_uint8(tvb, offset); + proto_tree_add_item(tree, hf_nmf_negotiate_type, + tvb, offset, 1, ENC_NA); + offset += 1; + if (type == 0x14) { + nmf_info->fnum_negotiated = pinfo->fd->num; + } + + offset += 2; + + len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_nmf_negotiate_length, + tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + col_add_fstr(pinfo->cinfo, COL_INFO, + "Upgraded Packet rlen: %u (0x%x)", + (unsigned)rlen, (unsigned)rlen); + proto_item_append_text(item, ", Upgraded Packet rlen: %u (0x%x) len: %u (0x%x) type: 0x%02x", + (unsigned)rlen, (unsigned)rlen, + (unsigned)len, (unsigned)len, + (unsigned)type); + negotiate_tvb = tvb_new_subset_length(tvb, offset, len); + + call_dissector(gssapi_handle, negotiate_tvb, pinfo, tree); + offset += len; + return offset; + } + + return dissect_nmf_record(tvb, pinfo, nmf_info, tree, 0); +} + +static int +dissect_nmf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, _U_ void *_unused) +{ + conversation_t *conv = NULL; + nmf_conv_info_t *nmf_info = NULL; + proto_tree *tree = NULL; + proto_item *item = NULL; + + conv = find_or_create_conversation(pinfo); + nmf_info = (nmf_conv_info_t *)conversation_get_proto_data(conv, + proto_nmf); + if (nmf_info == NULL) { + nmf_info = wmem_new0(wmem_file_scope(), nmf_conv_info_t); + nmf_info->fnum_upgraded = 0xffffffff; + nmf_info->fnum_negotiated = 0xffffffff; + conversation_add_proto_data(conv, proto_nmf, nmf_info); + } + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "NMF"); + col_set_str(pinfo->cinfo, COL_INFO, "NMF..."); + + if (parent_tree != NULL) { + item = proto_tree_add_item(parent_tree, proto_nmf, tvb, 0, -1, ENC_NA); + tree = proto_item_add_subtree(item, ett_nmf); + } + + tcp_dissect_pdus(tvb, pinfo, tree, nmf_reassemble, + 1, /* fixed_length */ + nmf_get_pdu_len, + dissect_nmf_pdu, + nmf_info); + return tvb_captured_length(tvb); +} + +void proto_register_nmf(void) +{ + static int *ett[] = { + &ett_nmf, + &ett_nmf_payload, + }; + static hf_register_info hf[] = { + { &hf_nmf_record, + { "Record", "nmf.record", + FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_nmf_record_type, + { "Type", "nmf.type", + FT_UINT8, BASE_DEC, VALS(record_types), 0, NULL, HFILL }}, + { &hf_nmf_version_major, + { "Version Major", "nmf.version.major", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + { &hf_nmf_version_minor, + { "Version minor", "nmf.version.minor", + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }}, + { &hf_nmf_mode_value, + { "Mode", "nmf.mode.value", + FT_UINT8, BASE_DEC, VALS(mode_values), 0, NULL, HFILL }}, + { &hf_nmf_via_length, + { "Length", "nmf.via.length", + FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_nmf_via_value, + { "URI", "nmf.via.uri", + FT_STRING, BASE_NONE, NULL, 0x0, "Via URI", HFILL }}, + { &hf_nmf_known_mode_value, + { "Mode", "nmf.known_mode.value", + FT_UINT8, BASE_DEC, VALS(known_mode_values), 0, NULL, HFILL }}, + { &hf_nmf_sized_envelope_length, + { "Length", "nmf.sized_envelope.length", + FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_nmf_upgrade_length, + { "Length", "nmf.upgrade.length", + FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_nmf_upgrade_protocol, + { "Upgrade Protocol", "nmf.upgrade.protocol", + FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, + { &hf_nmf_negotiate_type, + { "Negotiate Type", "nmf.negotiate.type", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }}, + { &hf_nmf_negotiate_length, + { "Negotiate Length", "nmf.negotiate.length", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + { &hf_nmf_protect_length, + { "Protect Length", "nmf.protect.length", + FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, + }; + module_t *nmf_module = NULL; + + proto_nmf = proto_register_protocol("NMF (.NET Message Framing Protocol)", + "NMF", "nmf"); + proto_register_subtree_array(ett, array_length(ett)); + proto_register_field_array(proto_nmf, hf, array_length(hf)); + + nmf_module = prefs_register_protocol(proto_nmf, NULL); + + expert_module_t *expert_nmf; + static ei_register_info ei[] = { + { &ei_nmf_bad_record_size, + { "nmf.bad_record_size", PI_MALFORMED, PI_WARN, "Invalid record size varint", EXPFILL }}, + }; + + expert_nmf = expert_register_protocol(proto_nmf); + expert_register_field_array(expert_nmf, ei, array_length(ei)); + + prefs_register_bool_preference(nmf_module, + "reassemble_nmf", + "Reassemble NMF fragments", + "Whether the NMF dissector should reassemble fragmented payloads", + &nmf_reassemble); +} + + +void +proto_reg_handoff_nmf(void) +{ + dissector_handle_t nmf_handle; + + nmf_handle = create_dissector_handle(dissect_nmf, proto_nmf); + dissector_add_uint_with_preference("tcp.port", NMF_PORT, nmf_handle); + + gssapi_handle = find_dissector_add_dependency("gssapi", proto_nmf); + gssapi_wrap_handle = find_dissector_add_dependency("gssapi_verf", proto_nmf); + + xml_handle = find_dissector_add_dependency("xml", proto_nmf); +} -- cgit v1.2.3