Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-nmf.c
Line
Count
Source
1
/*
2
 * packet-nmf.c
3
 *
4
 * Routines for [MC-NMF] .NET Message Framing Protocol
5
 *
6
 * Copyright 2017 Stefan Metzmacher <metze@samba.org>
7
 *
8
 * SPDX-License-Identifier: GPL-2.0-or-later
9
 */
10
11
#include "config.h"
12
13
#include <wsutil/str_util.h>
14
#include <epan/packet.h>
15
#include <epan/prefs.h>
16
#include <epan/expert.h>
17
#include <epan/proto_data.h>
18
#include "packet-tcp.h"
19
#include "packet-windows-common.h"
20
#include "packet-gssapi.h"
21
22
16
#define NMF_PORT 9389
23
24
void proto_register_nmf(void);
25
void proto_reg_handoff_nmf(void);
26
27
static dissector_handle_t gssapi_handle;
28
static dissector_handle_t gssapi_wrap_handle;
29
30
static dissector_handle_t xml_handle;
31
32
static int proto_nmf;
33
34
static int ett_nmf;
35
static int ett_nmf_payload;
36
37
static int hf_nmf_record;
38
static int hf_nmf_record_type;
39
static int hf_nmf_version_major;
40
static int hf_nmf_version_minor;
41
static int hf_nmf_mode_value;
42
static int hf_nmf_via_length;
43
static int hf_nmf_via_value;
44
static int hf_nmf_known_mode_value;
45
static int hf_nmf_sized_envelope_length;
46
static int hf_nmf_upgrade_length;
47
static int hf_nmf_upgrade_protocol;
48
static int hf_nmf_negotiate_type;
49
static int hf_nmf_negotiate_length;
50
static int hf_nmf_protect_length;
51
52
static expert_field ei_nmf_bad_record_size;
53
54
static bool nmf_reassemble = true;
55
56
enum nmf_record_type {
57
  NMF_VERSION_RECORD    = 0x00,
58
  NMF_MODE_RECORD     = 0x01,
59
  NMF_VIA_RECORD      = 0x02,
60
  NMF_KNOWN_ENCODING_RECORD = 0x03,
61
  NMF_EXTENSIBLE_ENCODING_RECORD  = 0x04,
62
  NMF_UNSIZED_ENVELOPE_RECORD = 0x05,
63
  NMF_SIZED_ENVELOPE_RECORD = 0x06,
64
  NMF_END_RECORD      = 0x07,
65
  NMF_FAULT_RECORD    = 0x08,
66
  NMF_UPGRADE_REQUEST_RECORD  = 0x09,
67
  NMF_UPGRADE_RESPONSE_RECORD = 0x0A,
68
  NMF_PREAMBLE_ACK_RECORD   = 0x0B,
69
  NMF_PREAMBLE_END_RECORD   = 0x0C
70
};
71
72
static const value_string record_types[] = {
73
  { NMF_VERSION_RECORD,     "Version Record"},
74
  { NMF_MODE_RECORD,      "Mode Record"},
75
  { NMF_VIA_RECORD,     "Via Record"},
76
  { NMF_KNOWN_ENCODING_RECORD,    "Known Encoding Record"},
77
  { NMF_EXTENSIBLE_ENCODING_RECORD, "Extensible Encoding Record"},
78
  { NMF_UNSIZED_ENVELOPE_RECORD,    "Unsized Envelope Record"},
79
  { NMF_SIZED_ENVELOPE_RECORD,    "Sized Envelope Record"},
80
  { NMF_END_RECORD,     "End Record"},
81
  { NMF_FAULT_RECORD,     "Fault Record"},
82
  { NMF_UPGRADE_REQUEST_RECORD,   "Upgrade Request Record"},
83
  { NMF_UPGRADE_RESPONSE_RECORD,    "Upgrade Response Record"},
84
  { NMF_PREAMBLE_ACK_RECORD,    "Preamble Ack Record"},
85
  { NMF_PREAMBLE_END_RECORD,    "Preamble End Record"},
86
  { 0, NULL }
87
};
88
89
static const value_string mode_values[] = {
90
  { 0x01,   "Singleton-Unsized"},
91
  { 0x02,   "Duplex"},
92
  { 0x03,   "Simplex"},
93
  { 0, NULL }
94
};
95
96
static const value_string known_mode_values[] = {
97
  { 0x00,   "SOAP 1.1 UTF-8"},
98
  { 0x01,   "SOAP 1.1 UTF-16"},
99
  { 0x02,   "SOAP 1.1 Unicode Little-Endian"},
100
  { 0x03,   "SOAP 1.2 UTF-8"},
101
  { 0x04,   "SOAP 1.2 UTF-16"},
102
  { 0x05,   "SOAP 1.2 Unicode Little-Endian"},
103
  { 0x06,   "SOAP 1.2 MOTM"},
104
  { 0x07,   "SOAP 1.2 Binary"},
105
  { 0x08,   "SOAP 1.2 Binary with in-band dictionary"},
106
  { 0, NULL }
107
};
108
109
typedef struct nmf_conv_info_t {
110
  uint32_t fnum_upgraded;
111
  uint32_t fnum_negotiated;
112
} nmf_conv_info_t;
113
114
/* Read the the varint holding the record size.
115
 * Callers MUST check for a 0 return value, which indicates that
116
 * parsing the varint failed, to avoid infinite loops.
117
 */
118
static int
119
dissect_nmf_record_size(tvbuff_t *tvb, proto_tree *tree,
120
      int hf_index, int offset, uint32_t *_size)
121
344
{
122
344
  uint64_t size = 0;
123
344
  int start_offset = offset;
124
125
  /* 5 is the encoded size for UINT32_MAX (but can also contain larger
126
   * varints).
127
   */
128
344
  unsigned len = tvb_get_varint(tvb, offset, 5, &size, ENC_VARINT_PROTOBUF);
129
344
  if (len == 0) {
130
9
    proto_tree_add_expert_format(tree, NULL, &ei_nmf_bad_record_size, tvb, offset, 5,
131
9
      "Invalid record size; varint does not end in five bytes");
132
9
    return 0;
133
9
  }
134
335
  if  (size > UINT32_MAX) {
135
2
    proto_tree_add_expert_format(tree, NULL, &ei_nmf_bad_record_size, tvb, offset, len,
136
2
      "Invalid record size %" PRIu64, size);
137
2
    return 0;
138
2
  }
139
140
333
  if (_size != NULL) {
141
333
    *_size = (uint32_t)size;
142
333
  }
143
144
333
  if (tree != NULL && hf_index != -1) {
145
333
    proto_item *item = NULL;
146
333
    item = proto_tree_add_item(tree, hf_index, tvb,
147
333
             start_offset, -1, ENC_NA);
148
333
    proto_item_set_len(item, (int)len);
149
333
    proto_item_append_text(item, ": %u (0x%x)",
150
333
               (unsigned)size, (unsigned)size);
151
333
  }
152
153
333
  return offset;
154
335
}
155
156
static int
157
dissect_nmf_record(tvbuff_t *tvb, packet_info *pinfo,
158
       nmf_conv_info_t *nmf_info,
159
       proto_tree *tree, int offset)
160
7.30k
{
161
7.30k
  proto_item *record_item = NULL;
162
7.30k
  proto_tree *record_tree = NULL;
163
7.30k
  const char *record_name = NULL;
164
7.30k
  enum nmf_record_type record_type;
165
7.30k
  uint32_t size = 0;
166
7.30k
  const uint8_t *str = NULL;
167
7.30k
  tvbuff_t *payload_tvb = NULL;
168
169
7.30k
  record_item = proto_tree_add_item(tree, hf_nmf_record, tvb, offset, -1, ENC_NA);
170
7.30k
  proto_item_append_text(record_item, ", start_offset=0x%x, ", (unsigned)offset);
171
7.30k
  record_tree = proto_item_add_subtree(record_item, ett_nmf);
172
173
7.30k
  record_type = (enum nmf_record_type)tvb_get_uint8(tvb, offset);
174
7.30k
  record_name = val_to_str_const((uint32_t)record_type, record_types,
175
7.30k
               "Unknown Record");
176
7.30k
  proto_tree_add_item(record_tree, hf_nmf_record_type,
177
7.30k
          tvb, offset, 1, ENC_NA);
178
7.30k
  offset += 1;
179
180
7.30k
  col_append_str(pinfo->cinfo, COL_INFO, record_name);
181
7.30k
  proto_item_append_text(record_item, "%s", record_name);
182
183
7.30k
  switch (record_type) {
184
1.25k
  case NMF_VERSION_RECORD:
185
1.25k
    proto_tree_add_item(record_tree, hf_nmf_version_major,
186
1.25k
            tvb, offset, 1, ENC_NA);
187
1.25k
    offset += 1;
188
1.25k
    proto_tree_add_item(record_tree, hf_nmf_version_minor,
189
1.25k
            tvb, offset, 1, ENC_NA);
190
1.25k
    offset += 1;
191
1.25k
    break;
192
339
  case NMF_MODE_RECORD:
193
339
    proto_tree_add_item(record_tree, hf_nmf_mode_value,
194
339
            tvb, offset, 1, ENC_NA);
195
339
    offset += 1;
196
339
    break;
197
128
  case NMF_VIA_RECORD:
198
128
    offset = dissect_nmf_record_size(tvb, record_tree,
199
128
             hf_nmf_via_length,
200
128
             offset, &size);
201
128
    if (offset <= 0) {
202
6
      return -1;
203
6
    }
204
205
122
    proto_tree_add_item_ret_string(record_tree, hf_nmf_via_value,
206
122
                 tvb, offset, size, ENC_UTF_8,
207
122
                 pinfo->pool, &str);
208
122
    offset += size;
209
122
    proto_item_append_text(record_item, ": %s", (const char *)str);
210
122
    break;
211
124
  case NMF_KNOWN_ENCODING_RECORD:
212
124
    proto_tree_add_item(record_tree, hf_nmf_known_mode_value,
213
124
            tvb, offset, 1, ENC_NA);
214
124
    offset += 1;
215
124
    break;
216
37
  case NMF_EXTENSIBLE_ENCODING_RECORD:
217
    /* TODO */
218
37
    break;
219
148
  case NMF_UNSIZED_ENVELOPE_RECORD:
220
    /* TODO */
221
148
    break;
222
173
  case NMF_SIZED_ENVELOPE_RECORD:
223
173
    offset = dissect_nmf_record_size(tvb, record_tree,
224
173
             hf_nmf_sized_envelope_length,
225
173
             offset, &size);
226
173
    if (offset <= 0) {
227
2
      return -1;
228
2
    }
229
230
171
    payload_tvb = tvb_new_subset_length(tvb, offset, size);
231
171
    offset += size;
232
171
    proto_item_append_text(record_item, ": Payload (%u byte%s)",
233
171
               size, plurality(size, "", "s"));
234
171
    proto_tree_add_format_text(record_tree, payload_tvb, 0, size);
235
#if 0
236
    tvbuff_t *xml_tvb = NULL;
237
    if (0) {
238
      /* TODO:
239
       *
240
       * 1. reassemble payload
241
       * 2. use
242
       *    [MC-NBFSE] .NET Binary Format: SOAP Extension
243
       *    [MC-NBFS]  .NET Binary Format: SOAP Data Structure
244
       *    [MC-NBFX]  .NET Binary Format: XML Data Structure
245
       *    to generate XML
246
       * 3. call the XML dissector.
247
       */
248
      if (payload_tvb != NULL) {
249
        xml_tvb = NULL;
250
      }
251
    }
252
    if (xml_tvb != NULL) {
253
      call_dissector_with_data(xml_handle, xml_tvb, pinfo,
254
                   record_tree, NULL);
255
    }
256
#endif
257
171
    break;
258
82
  case NMF_END_RECORD:
259
    /* TODO */
260
82
    break;
261
29
  case NMF_FAULT_RECORD:
262
    /* TODO */
263
29
    break;
264
43
  case NMF_UPGRADE_REQUEST_RECORD:
265
43
    offset = dissect_nmf_record_size(tvb, record_tree,
266
43
             hf_nmf_upgrade_length,
267
43
             offset, &size);
268
43
    if (offset <= 0) {
269
3
      return -1;
270
3
    }
271
272
40
    proto_tree_add_item_ret_string(record_tree, hf_nmf_upgrade_protocol,
273
40
                 tvb, offset, size, ENC_UTF_8,
274
40
                 pinfo->pool, &str);
275
40
    offset += size;
276
40
    proto_item_append_text(record_item, ": %s", (const char *)str);
277
40
    break;
278
279
117
  case NMF_UPGRADE_RESPONSE_RECORD:
280
117
    nmf_info->fnum_upgraded = pinfo->fd->num;
281
117
    break;
282
17
  case NMF_PREAMBLE_ACK_RECORD:
283
    /* TODO */
284
17
    break;
285
47
  case NMF_PREAMBLE_END_RECORD:
286
    /* TODO */
287
47
    break;
288
7.30k
  }
289
290
7.26k
  proto_item_append_text(record_item, ", end_offset=0x%x", (unsigned)offset);
291
7.26k
  proto_item_set_end(record_item, tvb, offset);
292
293
7.26k
  return offset;
294
7.30k
}
295
296
static unsigned
297
nmf_get_pdu_len(packet_info *pinfo, tvbuff_t *parent_tvb, int parent_offset, void *_info)
298
7.30k
{
299
7.30k
  nmf_conv_info_t *nmf_info = (nmf_conv_info_t *)_info;
300
7.30k
  enum nmf_record_type record_type;
301
7.30k
  tvbuff_t *tvb = tvb_new_subset_remaining(parent_tvb, parent_offset);
302
7.30k
  unsigned offset = 0;
303
304
7.30k
  if (pinfo->fd->num > nmf_info->fnum_negotiated) {
305
0
    unsigned remaining = tvb_captured_length(tvb);
306
0
    unsigned len = 0;
307
0
    unsigned needed = 0;
308
309
0
    if (remaining < 4) {
310
0
      return 0;
311
0
    }
312
313
0
    len = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN);
314
315
0
    needed = 4 + len;
316
0
    return needed;
317
0
  }
318
319
7.30k
  if (pinfo->fd->num > nmf_info->fnum_upgraded) {
320
3
    unsigned remaining = tvb_captured_length(tvb);
321
3
    unsigned len = 0;
322
3
    unsigned needed = 0;
323
324
3
    if (remaining < 5) {
325
0
      return 0;
326
0
    }
327
328
3
    offset += 3;
329
330
3
    len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
331
332
3
    needed = 5 + len;
333
3
    return needed;
334
3
  }
335
336
7.30k
  record_type = (enum nmf_record_type)tvb_get_uint8(tvb, offset);
337
7.30k
  offset += 1;
338
339
7.30k
  switch (record_type) {
340
131
  case NMF_VIA_RECORD:
341
306
  case NMF_SIZED_ENVELOPE_RECORD:
342
349
  case NMF_UPGRADE_REQUEST_RECORD:
343
349
        {
344
    /* Variable sized record. We must not throw an exception. */
345
349
    uint64_t size = 0;
346
349
    unsigned len = tvb_get_varint(tvb, offset,
347
349
                tvb_captured_length_remaining(tvb, offset),
348
349
                &size, ENC_VARINT_PROTOBUF);
349
    /* [MC-NMF] 2.2.2 The record length can be up to UINT32_MAX,
350
     * with an encoded size of 5 bytes.
351
     */
352
349
    if (len == 0) {
353
      /* Parsing failed. */
354
7
      if (tvb_captured_length_remaining(tvb, offset) < 5) {
355
        /* Fewer than five bytes, so ask for one more segment. */
356
5
        return 0;
357
5
      }
358
359
      /* We had at least 5 bytes, so the length is invalid.
360
       * Just take the rest of this segment.
361
       * The expert info will be handled in the main dissection
362
       * routine. */
363
2
      return tvb_reported_length(tvb);
364
7
    }
365
342
    offset += len;
366
342
    if (/*size > UINT32_MAX || */ ckd_add(&offset, offset, size)) {
367
      /* Invalid length or overflow. A size > UINT32_MAX
368
       * will always overflow so we don't need to check
369
       * unless we want to distinguish the two cases. */
370
9
      return tvb_reported_length(tvb);
371
9
    }
372
333
    break;
373
342
        }
374
1.25k
  case NMF_VERSION_RECORD:
375
1.25k
    offset += 2;
376
1.25k
    break;
377
339
  case NMF_MODE_RECORD:
378
339
    offset += 1;
379
339
    break;
380
124
  case NMF_KNOWN_ENCODING_RECORD:
381
124
    offset += 1;
382
124
    break;
383
37
  case NMF_EXTENSIBLE_ENCODING_RECORD:
384
    /* TODO */
385
37
    break;
386
148
  case NMF_UNSIZED_ENVELOPE_RECORD:
387
    /* TODO */
388
148
    break;
389
82
  case NMF_END_RECORD:
390
    /* TODO */
391
82
    break;
392
29
  case NMF_FAULT_RECORD:
393
    /* TODO */
394
29
    break;
395
117
  case NMF_UPGRADE_RESPONSE_RECORD:
396
117
    break;
397
17
  case NMF_PREAMBLE_ACK_RECORD:
398
    /* TODO */
399
17
    break;
400
47
  case NMF_PREAMBLE_END_RECORD:
401
    /* TODO */
402
47
    break;
403
7.30k
  }
404
405
7.28k
  return offset;
406
7.30k
}
407
408
static int
409
dissect_nmf_payload(tvbuff_t *tvb, packet_info *pinfo,
410
        proto_tree *tree, nmf_conv_info_t *nmf_info)
411
0
{
412
0
  unsigned offset = 0;
413
414
0
  while (tvb_reported_length_remaining(tvb, offset) > 0) {
415
0
    int ret;
416
417
0
    ret = dissect_nmf_record(tvb, pinfo, nmf_info, tree, offset);
418
0
    if (ret <= 0) {
419
0
      return -1;
420
0
    }
421
0
    offset += ret;
422
0
  }
423
424
0
  return offset;
425
0
}
426
427
static int
428
dissect_nmf_pdu(tvbuff_t *tvb, packet_info *pinfo,
429
    proto_tree *tree, void *_info)
430
7.30k
{
431
7.30k
  nmf_conv_info_t *nmf_info = (nmf_conv_info_t *)_info;
432
433
7.30k
  pinfo->fragmented = true;
434
435
7.30k
  if (pinfo->fd->num > nmf_info->fnum_negotiated) {
436
0
    proto_item *item = proto_tree_get_parent(tree);
437
0
    uint32_t len = 0;
438
0
    unsigned offset = 0;
439
0
    tvbuff_t *gssapi_tvb = NULL;
440
0
    tvbuff_t *plain_tvb = NULL, *decr_tvb= NULL;
441
0
    int ver_len;
442
0
    gssapi_encrypt_info_t gssapi_encrypt;
443
444
0
    len = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN);
445
0
    proto_tree_add_item(tree, hf_nmf_negotiate_length,
446
0
            tvb, offset, 4, ENC_LITTLE_ENDIAN);
447
0
    offset += 4;
448
449
0
    col_set_str(pinfo->cinfo, COL_INFO, "NMF GSSAPI");
450
0
    col_add_fstr(pinfo->cinfo, COL_INFO,
451
0
           "Protected Packet len: %u (0x%x)",
452
0
           (unsigned)len, (unsigned)len);
453
0
    proto_item_append_text(item, ", Protected Packet len: %u (0x%x)",
454
0
        (unsigned)len, (unsigned)len);
455
456
0
    gssapi_tvb = tvb_new_subset_length(tvb, offset, len);
457
0
    offset += len;
458
459
    /* Attempt decryption of the GSSAPI wrapped data if possible */
460
0
    memset(&gssapi_encrypt, 0, sizeof(gssapi_encrypt));
461
0
    gssapi_encrypt.decrypt_gssapi_tvb=DECRYPT_GSSAPI_NORMAL;
462
463
0
    ver_len = call_dissector_with_data(gssapi_wrap_handle, gssapi_tvb,
464
0
                     pinfo, tree, &gssapi_encrypt);
465
    /* if we could unwrap, do a tvb shuffle */
466
0
    if (gssapi_encrypt.gssapi_decrypted_tvb) {
467
0
      decr_tvb=gssapi_encrypt.gssapi_decrypted_tvb;
468
0
    } else if (gssapi_encrypt.gssapi_wrap_tvb) {
469
0
      plain_tvb=gssapi_encrypt.gssapi_wrap_tvb;
470
0
    }
471
472
    /*
473
    * if we don't have unwrapped data,
474
    * see if the wrapping involved encryption of the
475
    * data; if not, just use the plaintext data.
476
    */
477
0
    if (!decr_tvb && !plain_tvb) {
478
0
      if(!gssapi_encrypt.gssapi_data_encrypted){
479
0
         plain_tvb = tvb_new_subset_remaining(gssapi_tvb, ver_len);
480
0
      }
481
0
    }
482
483
0
    if (decr_tvb) {
484
0
      proto_tree *enc_tree = NULL;
485
0
      unsigned decr_len = tvb_reported_length(decr_tvb);
486
487
0
      col_set_str(pinfo->cinfo, COL_INFO, "NMF GSS-API Privacy (decrypted): ");
488
489
0
      if (tree) {
490
0
        enc_tree = proto_tree_add_subtree_format(tree, decr_tvb, 0, -1,
491
0
                   ett_nmf_payload, NULL,
492
0
                   "GSS-API Encrypted payload (%d byte%s)",
493
0
                   decr_len,
494
0
                   plurality(decr_len, "", "s"));
495
0
      }
496
0
      dissect_nmf_payload(decr_tvb, pinfo, enc_tree, nmf_info);
497
0
    } else if (plain_tvb) {
498
0
      proto_tree *plain_tree = NULL;
499
0
      unsigned plain_len = tvb_reported_length(plain_tvb);
500
501
0
      col_set_str(pinfo->cinfo, COL_INFO, "NMF GSS-API Integrity: ");
502
503
0
      if (tree) {
504
0
        plain_tree = proto_tree_add_subtree_format(tree, plain_tvb, 0, -1,
505
0
                     ett_nmf_payload, NULL,
506
0
                     "GSS-API payload (%d byte%s)",
507
0
                     plain_len,
508
0
                     plurality(plain_len, "", "s"));
509
0
      }
510
511
0
      dissect_nmf_payload(plain_tvb, pinfo, plain_tree, nmf_info);
512
0
    } else {
513
0
      col_add_fstr(pinfo->cinfo, COL_INFO, "NMF GSS-API Privacy: payload (%d byte%s)",
514
0
             len, plurality(len, "", "s"));
515
516
0
      proto_tree_add_format_text(tree, gssapi_tvb, 0, len);
517
0
    }
518
0
    return offset;
519
0
  }
520
521
7.30k
  if (pinfo->fd->num > nmf_info->fnum_upgraded) {
522
3
    proto_item *item = proto_tree_get_parent(tree);
523
3
    unsigned rlen = tvb_reported_length(tvb);
524
3
    uint16_t len = 0;
525
3
    uint8_t type;
526
3
    unsigned offset = 0;
527
3
    tvbuff_t *negotiate_tvb = NULL;
528
529
3
    col_set_str(pinfo->cinfo, COL_INFO, "NMF Upgrade");
530
531
3
    type = tvb_get_uint8(tvb, offset);
532
3
    proto_tree_add_item(tree, hf_nmf_negotiate_type,
533
3
            tvb, offset, 1, ENC_NA);
534
3
    offset += 1;
535
3
    if (type == 0x14) {
536
0
      nmf_info->fnum_negotiated = pinfo->fd->num;
537
0
    }
538
539
3
    offset += 2;
540
541
3
    len = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
542
3
    proto_tree_add_item(tree, hf_nmf_negotiate_length,
543
3
            tvb, offset, 2, ENC_BIG_ENDIAN);
544
3
    offset += 2;
545
546
3
    col_add_fstr(pinfo->cinfo, COL_INFO,
547
3
           "Upgraded Packet rlen: %u (0x%x)",
548
3
           (unsigned)rlen, (unsigned)rlen);
549
3
    proto_item_append_text(item, ", Upgraded Packet rlen: %u (0x%x) len: %u (0x%x) type: 0x%02x",
550
3
        (unsigned)rlen, (unsigned)rlen,
551
3
        (unsigned)len, (unsigned)len,
552
3
        (unsigned)type);
553
3
    negotiate_tvb = tvb_new_subset_length(tvb, offset, len);
554
555
3
    call_dissector(gssapi_handle, negotiate_tvb, pinfo, tree);
556
3
    offset += len;
557
3
    return offset;
558
3
  }
559
560
7.30k
  return dissect_nmf_record(tvb, pinfo, nmf_info, tree, 0);
561
7.30k
}
562
563
static int
564
dissect_nmf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, _U_ void *_unused)
565
67
{
566
67
  conversation_t *conv = NULL;
567
67
  nmf_conv_info_t *nmf_info = NULL;
568
67
  proto_tree *tree = NULL;
569
67
  proto_item *item = NULL;
570
571
67
  conv = find_or_create_conversation(pinfo);
572
67
  nmf_info = (nmf_conv_info_t *)conversation_get_proto_data(conv,
573
67
                  proto_nmf);
574
67
  if (nmf_info == NULL) {
575
53
    nmf_info = wmem_new0(wmem_file_scope(), nmf_conv_info_t);
576
53
    nmf_info->fnum_upgraded = 0xffffffff;
577
53
    nmf_info->fnum_negotiated = 0xffffffff;
578
53
    conversation_add_proto_data(conv, proto_nmf, nmf_info);
579
53
  }
580
581
67
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "NMF");
582
67
  col_set_str(pinfo->cinfo, COL_INFO, "NMF...");
583
584
67
  if (parent_tree != NULL) {
585
67
    item = proto_tree_add_item(parent_tree, proto_nmf, tvb, 0, -1, ENC_NA);
586
67
    tree = proto_item_add_subtree(item, ett_nmf);
587
67
  }
588
589
67
  tcp_dissect_pdus(tvb, pinfo, tree, nmf_reassemble,
590
67
       1, /* fixed_length */
591
67
       nmf_get_pdu_len,
592
67
       dissect_nmf_pdu,
593
67
       nmf_info);
594
67
  return tvb_captured_length(tvb);
595
67
}
596
597
void proto_register_nmf(void)
598
16
{
599
16
  static int *ett[] = {
600
16
    &ett_nmf,
601
16
    &ett_nmf_payload,
602
16
  };
603
16
  static hf_register_info hf[] = {
604
16
  { &hf_nmf_record,
605
16
    { "Record", "nmf.record",
606
16
    FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
607
16
  { &hf_nmf_record_type,
608
16
    { "Type", "nmf.type",
609
16
    FT_UINT8, BASE_DEC, VALS(record_types), 0, NULL, HFILL }},
610
16
  { &hf_nmf_version_major,
611
16
    { "Version Major", "nmf.version.major",
612
16
    FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
613
16
  { &hf_nmf_version_minor,
614
16
    { "Version minor", "nmf.version.minor",
615
16
    FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
616
16
  { &hf_nmf_mode_value,
617
16
    { "Mode", "nmf.mode.value",
618
16
    FT_UINT8, BASE_DEC, VALS(mode_values), 0, NULL, HFILL }},
619
16
  { &hf_nmf_via_length,
620
16
    { "Length", "nmf.via.length",
621
16
    FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
622
16
  { &hf_nmf_via_value,
623
16
    { "URI", "nmf.via.uri",
624
16
    FT_STRING, BASE_NONE, NULL, 0x0, "Via URI", HFILL }},
625
16
  { &hf_nmf_known_mode_value,
626
16
    { "Mode", "nmf.known_mode.value",
627
16
    FT_UINT8, BASE_DEC, VALS(known_mode_values), 0, NULL, HFILL }},
628
16
  { &hf_nmf_sized_envelope_length,
629
16
    { "Length", "nmf.sized_envelope.length",
630
16
    FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
631
16
  { &hf_nmf_upgrade_length,
632
16
    { "Length", "nmf.upgrade.length",
633
16
    FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
634
16
  { &hf_nmf_upgrade_protocol,
635
16
    { "Upgrade Protocol", "nmf.upgrade.protocol",
636
16
    FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
637
16
  { &hf_nmf_negotiate_type,
638
16
    { "Negotiate Type", "nmf.negotiate.type",
639
16
    FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
640
16
  { &hf_nmf_negotiate_length,
641
16
    { "Negotiate Length", "nmf.negotiate.length",
642
16
    FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
643
16
  { &hf_nmf_protect_length,
644
16
    { "Protect Length", "nmf.protect.length",
645
16
    FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
646
16
  };
647
16
  module_t *nmf_module = NULL;
648
649
16
  proto_nmf = proto_register_protocol("NMF (.NET Message Framing Protocol)",
650
16
              "NMF", "nmf");
651
16
  proto_register_subtree_array(ett, array_length(ett));
652
16
  proto_register_field_array(proto_nmf, hf, array_length(hf));
653
654
16
  nmf_module = prefs_register_protocol(proto_nmf, NULL);
655
656
16
  expert_module_t *expert_nmf;
657
16
  static ei_register_info ei[] = {
658
16
    { &ei_nmf_bad_record_size,
659
16
    { "nmf.bad_record_size", PI_MALFORMED, PI_WARN, "Invalid record size varint", EXPFILL }},
660
16
  };
661
662
16
  expert_nmf = expert_register_protocol(proto_nmf);
663
16
  expert_register_field_array(expert_nmf, ei, array_length(ei));
664
665
16
  prefs_register_bool_preference(nmf_module,
666
16
               "reassemble_nmf",
667
16
               "Reassemble NMF fragments",
668
16
               "Whether the NMF dissector should reassemble fragmented payloads",
669
16
               &nmf_reassemble);
670
16
}
671
672
673
void
674
proto_reg_handoff_nmf(void)
675
16
{
676
16
  dissector_handle_t nmf_handle;
677
678
16
  nmf_handle = create_dissector_handle(dissect_nmf, proto_nmf);
679
16
  dissector_add_uint_with_preference("tcp.port", NMF_PORT, nmf_handle);
680
681
16
  gssapi_handle = find_dissector_add_dependency("gssapi", proto_nmf);
682
16
  gssapi_wrap_handle = find_dissector_add_dependency("gssapi_verf", proto_nmf);
683
684
16
  xml_handle = find_dissector_add_dependency("xml", proto_nmf);
685
16
}