Coverage Report

Created: 2026-01-02 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-telnet.c
Line
Count
Source
1
/* packet-telnet.c
2
 * Routines for Telnet packet dissection; see RFC 854 and RFC 855
3
 * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
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
/* Telnet authentication options as per     RFC2941
12
 * Kerberos v5 telnet authentication as per RFC2942
13
 * VMware Serial Port Proxy documented at https://developer.vmware.com/docs/11763/using-a-proxy-with-virtual-serial-ports
14
 */
15
#include "config.h"
16
17
#include <stdlib.h>
18
19
#include <epan/packet.h>
20
#include <epan/expert.h>
21
#include <epan/asn1.h>
22
#include <epan/tfs.h>
23
#include <wsutil/array.h>
24
#include <wsutil/str_util.h>
25
#include <wsutil/utf8_entities.h>
26
#include "packet-kerberos.h"
27
#include "packet-tls-utils.h"
28
#include "packet-tn3270.h"
29
#include "packet-tn5250.h"
30
#include "packet-acdr.h"
31
32
void proto_reg_handoff_telnet(void);
33
void proto_register_telnet(void);
34
35
static int proto_telnet;
36
static int hf_telnet_cmd;
37
static int hf_telnet_subcmd;
38
static int hf_telnet_auth_cmd;
39
static int hf_telnet_auth_name;
40
static int hf_telnet_auth_type;
41
static int hf_telnet_auth_mod_who;
42
static int hf_telnet_auth_mod_how;
43
static int hf_telnet_auth_mod_cred_fwd;
44
static int hf_telnet_auth_mod_enc;
45
static int hf_telnet_auth_krb5_type;
46
static int hf_telnet_auth_ssl_status;
47
static int hf_telnet_auth_data;
48
49
static int hf_telnet_string_subopt_value;
50
static int hf_telnet_naws_subopt_width;
51
static int hf_telnet_naws_subopt_height;
52
static int hf_telnet_outmark_subopt_cmd;
53
static int hf_telnet_outmark_subopt_banner;
54
static int hf_telnet_comport_subopt_signature;
55
static int hf_telnet_comport_subopt_baud_rate;
56
static int hf_telnet_comport_subopt_data_size;
57
static int hf_telnet_comport_subopt_parity;
58
static int hf_telnet_comport_subopt_stop;
59
static int hf_telnet_comport_subopt_control;
60
static int hf_telnet_comport_linestate;
61
static int hf_telnet_comport_set_linestate_mask;
62
static int hf_telnet_comport_modemstate;
63
static int hf_telnet_comport_set_modemstate_mask;
64
static int hf_telnet_comport_subopt_flow_control_suspend;
65
static int hf_telnet_comport_subopt_flow_control_resume;
66
static int hf_telnet_comport_subopt_purge;
67
static int hf_telnet_rfc_subopt_cmd;
68
static int hf_telnet_tabstop;
69
70
static int hf_telnet_enc_cmd;
71
static int hf_telnet_enc_type;
72
static int hf_telnet_enc_type_data;
73
static int hf_telnet_enc_key_id;
74
75
static int hf_telnet_data;
76
static int hf_telnet_option_data;
77
static int hf_telnet_subcommand_data;
78
79
static int hf_tn3270_subopt;
80
static int hf_tn3270_connect;
81
static int hf_tn3270_is;
82
static int hf_tn3270_request_string;
83
static int hf_tn3270_reason;
84
static int hf_tn3270_request;
85
static int hf_tn3270_regime_subopt_value;
86
static int hf_tn3270_regime_cmd;
87
88
static int hf_telnet_starttls;
89
90
static int hf_telnet_vmware_cmd;
91
static int hf_telnet_vmware_known_suboption_code;
92
static int hf_telnet_vmware_unknown_subopt_code;
93
static int hf_telnet_vmware_vmotion_sequence;
94
static int hf_telnet_vmware_vmotion_secret;
95
static int hf_telnet_vmware_proxy_direction;
96
static int hf_telnet_vmware_proxy_serviceUri;
97
static int hf_telnet_vmware_vm_vc_uuid;
98
static int hf_telnet_vmware_vm_bios_uuid;
99
static int hf_telnet_vmware_vm_location_uuid;
100
static int hf_telnet_vmware_vm_name;
101
102
static int ett_telnet;
103
static int ett_telnet_cmd;
104
static int ett_telnet_subopt;
105
static int ett_status_subopt;
106
static int ett_rcte_subopt;
107
static int ett_olw_subopt;
108
static int ett_ops_subopt;
109
static int ett_crdisp_subopt;
110
static int ett_htstops_subopt;
111
static int ett_htdisp_subopt;
112
static int ett_ffdisp_subopt;
113
static int ett_vtstops_subopt;
114
static int ett_vtdisp_subopt;
115
static int ett_lfdisp_subopt;
116
static int ett_extasc_subopt;
117
static int ett_bytemacro_subopt;
118
static int ett_det_subopt;
119
static int ett_supdupout_subopt;
120
static int ett_sendloc_subopt;
121
static int ett_termtype_subopt;
122
static int ett_tacacsui_subopt;
123
static int ett_outmark_subopt;
124
static int ett_tlocnum_subopt;
125
static int ett_tn3270reg_subopt;
126
static int ett_x3pad_subopt;
127
static int ett_naws_subopt;
128
static int ett_tspeed_subopt;
129
static int ett_rfc_subopt;
130
static int ett_linemode_subopt;
131
static int ett_xdpyloc_subopt;
132
static int ett_env_subopt;
133
static int ett_auth_subopt;
134
static int ett_enc_subopt;
135
static int ett_newenv_subopt;
136
static int ett_tn3270e_subopt;
137
static int ett_xauth_subopt;
138
static int ett_charset_subopt;
139
static int ett_rsp_subopt;
140
static int ett_comport_subopt;
141
static int ett_starttls_subopt;
142
143
static expert_field ei_telnet_suboption_length;
144
static expert_field ei_telnet_invalid_subcommand;
145
static expert_field ei_telnet_invalid_linestate;
146
static expert_field ei_telnet_invalid_stop;
147
static expert_field ei_telnet_enc_cmd_unknown;
148
static expert_field ei_telnet_invalid_data_size;
149
static expert_field ei_telnet_invalid_modemstate;
150
static expert_field ei_telnet_invalid_parity;
151
static expert_field ei_telnet_invalid_purge;
152
static expert_field ei_telnet_invalid_baud_rate;
153
static expert_field ei_telnet_invalid_control;
154
static expert_field ei_telnet_vmware_unexp_data;
155
156
static dissector_handle_t telnet_handle;
157
158
static dissector_handle_t tn3270_handle;
159
static dissector_handle_t tn5250_handle;
160
static dissector_handle_t tls_handle;
161
162
/* Some defines for Telnet */
163
164
14
#define TCP_PORT_TELNET 23
165
166
39.5k
#define TN_IAC   255
167
305
#define TN_DONT  254
168
273
#define TN_DO    253
169
121
#define TN_WONT  252
170
121
#define TN_WILL  251
171
11.3k
#define TN_SB    250
172
#define TN_GA    249
173
#define TN_EL    248
174
#define TN_EC    247
175
#define TN_AYT   246
176
#define TN_AO    245
177
#define TN_IP    244
178
#define TN_BRK   243
179
#define TN_DM    242
180
#define TN_NOP   241
181
8.89k
#define TN_SE    240
182
#define TN_EOR   239
183
#define TN_ABORT 238
184
#define TN_SUSP  237
185
#define TN_EOF   236
186
#define TN_ARE     1
187
188
static const value_string cmd_vals[] = {
189
  { TN_EOF,    "End of File" },
190
  { TN_SUSP,   "Suspend Current Process" },
191
  { TN_ABORT,  "Abort Process" },
192
  { TN_EOR,    "End of Record" },
193
  { TN_SE,     "Suboption End" },
194
  { TN_NOP,    "No Operation" },
195
  { TN_DM,     "Data Mark" },
196
  { TN_BRK,    "Break" },
197
  { TN_IP,     "Interrupt Process" },
198
  { TN_AO,     "Abort Output" },
199
  { TN_AYT,    "Are You There?" },
200
  { TN_EC,     "Escape Character" },
201
  { TN_EL,     "Erase Line" },
202
  { TN_GA,     "Go Ahead" },
203
  { TN_DONT,   "Don't" },
204
  { TN_DO,     "Do" },
205
  { TN_WONT,   "Won't" },
206
  { TN_WILL,   "Will" },
207
  { TN_SB,     "Suboption" },
208
  { 0, NULL }
209
};
210
211
typedef enum {
212
  NO_LENGTH,            /* option has no data, hence no length */
213
  FIXED_LENGTH,         /* option always has the same length */
214
  VARIABLE_LENGTH       /* option is variable-length - optlen is minimum */
215
} tn_opt_len_type;
216
217
/* Member of table of IP or TCP options. */
218
typedef struct tn_opt {
219
  const char      *name;          /* name of option */
220
  int             *subtree_index; /* pointer to subtree index for option */
221
  tn_opt_len_type  len_type;      /* type of option length field */
222
  int              optlen;        /* value length should be (minimum if VARIABLE) */
223
  void  (*dissect)(packet_info *pinfo, const char *, tvbuff_t *, int, int, proto_tree *, proto_item*);
224
                                  /* routine to dissect option */
225
} tn_opt;
226
227
typedef struct _telnet_conv_info {
228
  uint32_t  starttls_requested_in;  /* Frame of first sender of START_TLS FOLLOWS */
229
  uint32_t  starttls_port;          /* Source port for first sender */
230
  ssize_t   vmotion_sequence_len;   /* Length of "sequence" field for VMware vSPC vMotion. */
231
} telnet_conv_info_t;
232
233
static void
234
check_tn3270_model(packet_info *pinfo _U_, const char *terminaltype)
235
1
{
236
1
  int  model;
237
238
1
  if ((strcmp(terminaltype,"IBM-3278-2-E") == 0) || (strcmp(terminaltype,"IBM-3278-2") == 0) ||
239
1
      (strcmp(terminaltype,"IBM-3278-3") == 0) || (strcmp(terminaltype,"IBM-3278-4") == 0) ||
240
1
      (strcmp(terminaltype,"IBM-3278-5") == 0) || (strcmp(terminaltype,"IBM-3277-2") == 0) ||
241
1
      (strcmp(terminaltype,"IBM-3279-3") == 0) || (strcmp(terminaltype,"IBM-3279-4") == 0) ||
242
1
      (strcmp(terminaltype,"IBM-3279-2-E") == 0) || (strcmp(terminaltype,"IBM-3279-2") == 0) ||
243
1
      (strcmp(terminaltype,"IBM-3279-4-E") == 0)) {
244
0
    model = terminaltype[9] - '0';
245
0
    add_tn3270_conversation(pinfo, 0, model);
246
0
  }
247
1
}
248
249
static void
250
check_for_tn3270(packet_info *pinfo _U_, const char *optname, const char *terminaltype)
251
6
{
252
6
  if (strcmp(optname,"Terminal Type") != 0) {
253
6
    return;
254
6
  }
255
0
  check_tn3270_model(pinfo, terminaltype);
256
257
0
  if ((strcmp(terminaltype,"IBM-5555-C01") == 0) || /* 24 x 80 Double-Byte Character Set color display */
258
0
      (strcmp(terminaltype,"IBM-5555-B01") == 0) || /* 24 x 80 Double-Byte Character Set (DBCS)*/
259
0
      (strcmp(terminaltype,"IBM-3477-FC") == 0) ||  /* 27 x 132 color display*/
260
0
      (strcmp(terminaltype,"IBM-3477-FG") == 0) ||  /* 27 x 132 monochrome display*/
261
0
      (strcmp(terminaltype,"IBM-3180-2") == 0) ||   /* 27 x 132 monochrome display*/
262
0
      (strcmp(terminaltype,"IBM-3179-2") == 0) ||   /* 24 x 80 color display*/
263
0
      (strcmp(terminaltype,"IBM-3196-A1") == 0) ||  /* 24 x 80 monochrome display*/
264
0
      (strcmp(terminaltype,"IBM-5292-2") == 0) ||   /* 24 x 80 color display*/
265
0
      (strcmp(terminaltype,"IBM-5291-1") == 0) ||   /* 24 x 80 monochrome display*/
266
0
      (strcmp(terminaltype,"IBM-5251-11") == 0))    /* 24 x 80 monochrome display*/
267
0
    add_tn5250_conversation(pinfo, 0);
268
0
}
269
270
static telnet_conv_info_t *
271
telnet_get_session(packet_info *pinfo)
272
38
{
273
38
  conversation_t        *conversation = find_or_create_conversation(pinfo);
274
38
  telnet_conv_info_t    *telnet_info;
275
276
38
  telnet_info = (telnet_conv_info_t*)conversation_get_proto_data(conversation, proto_telnet);
277
38
  if (!telnet_info) {
278
8
    telnet_info = wmem_new0(wmem_file_scope(), telnet_conv_info_t);
279
8
    telnet_info->vmotion_sequence_len = -1;
280
8
    conversation_add_proto_data(conversation, proto_telnet, telnet_info);
281
8
  }
282
38
  return telnet_info;
283
38
}
284
285
/* Record some data/negotiation/subnegotiation in the "Info" column. */
286
static void
287
add_telnet_info_str(packet_info *pinfo, unsigned *num_items, const char *str)
288
14.8k
{
289
14.8k
  const unsigned max_info_items = 5; /* Arbitrary limit so the column doesn't end up too wide. */
290
291
14.8k
  if (*num_items == 0) {
292
    /* Replace the default info text. */
293
558
    col_add_str(pinfo->cinfo, COL_INFO, str);
294
14.3k
  } else if (*num_items < max_info_items) {
295
2.09k
    col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, str);
296
12.2k
  } else if (*num_items == max_info_items) {
297
    /* Too many to display.  Finish with an ellipsis. */
298
468
    col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, UTF8_HORIZONTAL_ELLIPSIS);
299
468
  }
300
14.8k
  (*num_items)++;
301
14.8k
}
302
303
/* Record in the "Info" column that a number of Telnet data bytes arrived. */
304
static void
305
add_telnet_data_bytes_str(packet_info *pinfo, unsigned *num_items, unsigned len)
306
6.02k
{
307
6.02k
  char str[30];
308
309
6.02k
  snprintf(str, sizeof str, "%u byte%s data", len, plurality(len, "", "s"));
310
6.02k
  add_telnet_info_str(pinfo, num_items, str);
311
6.02k
}
312
313
static void
314
dissect_string_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, int offset, int len,
315
                      proto_tree *tree, proto_item *item)
316
23
{
317
23
  uint8_t cmd;
318
319
23
  cmd = tvb_get_uint8(tvb, offset);
320
23
  switch (cmd) {
321
322
6
  case 0:       /* IS */
323
6
    proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Here's my %s", optname);
324
6
    offset++;
325
6
    len--;
326
6
    if (len > 0) {
327
6
      proto_tree_add_item(tree, hf_telnet_string_subopt_value, tvb, offset, len, ENC_ASCII);
328
6
    }
329
6
    check_for_tn3270(pinfo, optname, tvb_format_text(pinfo->pool, tvb, offset, len));
330
6
    break;
331
332
1
  case 1:       /* SEND */
333
1
    proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Send your %s", optname);
334
1
    offset++;
335
1
    len--;
336
1
    if (len > 0)
337
1
      proto_tree_add_bytes_format(tree, hf_telnet_subcommand_data, tvb, offset, len, NULL, "Extra data");
338
1
    break;
339
340
16
  default:
341
16
    expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
342
343
16
    offset++;
344
16
    len--;
345
16
    if (len > 0)
346
16
      proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
347
16
    break;
348
23
  }
349
23
}
350
351
static void
352
dissect_tn3270_regime_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, int offset,
353
                       int len, proto_tree *tree, proto_item *item _U_)
354
94
{
355
94
#define TN3270_REGIME_ARE          0x01
356
94
#define TN3270_REGIME_IS           0x00
357
358
94
  uint8_t cmd;
359
360
711
  while (len > 0) {
361
660
    cmd = tvb_get_uint8(tvb, offset);
362
660
    switch (cmd) {
363
12
    case TN3270_REGIME_ARE:
364
43
    case TN3270_REGIME_IS:
365
43
      if (cmd == TN3270_REGIME_ARE) {
366
12
        proto_tree_add_uint_format(tree, hf_tn3270_regime_cmd, tvb, offset, 1, cmd, "ARE");
367
12
        add_tn3270_conversation(pinfo, 0, 0);
368
31
      } else {
369
31
        proto_tree_add_uint_format(tree, hf_tn3270_regime_cmd, tvb, offset, 1, cmd, "IS");
370
31
      }
371
43
      proto_tree_add_item(tree, hf_tn3270_regime_subopt_value, tvb, offset + 1, len - 1, ENC_ASCII);
372
43
      return;
373
617
    default:
374
617
      proto_tree_add_uint_format(tree, hf_tn3270_regime_cmd, tvb, offset, 1, cmd, "Bogus value: %u", cmd);
375
617
      break;
376
660
    }
377
617
    offset++;
378
617
    len --;
379
617
  }
380
381
94
}
382
383
#define TN3270_ASSOCIATE          0x00
384
165
#define TN3270_CONNECT            0x01
385
607
#define TN3270_DEVICE_TYPE        0x02
386
366
#define TN3270_FUNCTIONS          0x03
387
208
#define TN3270_IS                 0x04
388
36
#define TN3270_REASON             0x05
389
#define TN3270_REJECT             0x06
390
399
#define TN3270_REQUEST            0x07
391
#define TN3270_SEND               0x08
392
/*       Reason_codes*/
393
#define TN3270_CONN_PARTNER       0x00
394
#define TN3270_DEVICE_IN_USE      0x01
395
#define TN3270_INV_ASSOCIATE      0x02
396
#define TN3270_INV_DEVICE_NAME    0x03
397
#define TN3270_INV_DEVICE_TYPE    0x04
398
#define TN3270_TYPE_NAME_ERROR    0x05
399
#define TN3270_UNKNOWN_ERROR      0x06
400
#define TN3270_UNSUPPORTED_REQ    0x07
401
/*       Function Names*/
402
#define TN3270_BIND_IMAGE         0x00
403
#define TN3270_DATA_STREAM_CTL    0x01
404
#define TN3270_RESPONSES          0x02
405
#define TN3270_SCS_CTL_CODES      0x03
406
#define TN3270_SYSREQ             0x04
407
408
static const value_string tn3270_subopt_vals[] = {
409
  { TN3270_ASSOCIATE,   "ASSOCIATE" },
410
  { TN3270_CONNECT,     "CONNECT" },
411
  { TN3270_DEVICE_TYPE, "DEVICE-TYPE" },
412
  { TN3270_FUNCTIONS,   "FUNCTIONS" },
413
  { TN3270_IS,          "IS" },
414
  { TN3270_REASON,      "REASON" },
415
  { TN3270_REJECT,      "REJECT" },
416
  { TN3270_REQUEST,     "REQUEST" },
417
  { TN3270_SEND,        "SEND" },
418
  { 0, NULL }
419
};
420
421
static const value_string tn3270_reason_vals[] = {
422
  { TN3270_CONN_PARTNER,    "CONN-PARTNER" },
423
  { TN3270_DEVICE_IN_USE,   "DEVICE-IN-USE" },
424
  { TN3270_INV_ASSOCIATE,   "INV-ASSOCIATE" },
425
  { TN3270_INV_DEVICE_NAME, "INV-DEVICE-NAME" },
426
  { TN3270_INV_DEVICE_TYPE, "INV-DEVICE-TYPE" },
427
  { TN3270_TYPE_NAME_ERROR, "TYPE-NAME-ERROR" },
428
  { TN3270_UNKNOWN_ERROR,   "UNKNOWN-ERROR" },
429
  { TN3270_UNSUPPORTED_REQ, "UNSUPPORTED-REQ" },
430
  { 0, NULL }
431
};
432
433
static const value_string tn3270_request_vals[] = {
434
  { TN3270_BIND_IMAGE,      "BIND-IMAGE" },
435
  { TN3270_DATA_STREAM_CTL, "DATA-STREAM-CTL" },
436
  { TN3270_RESPONSES,       "RESPONSES" },
437
  { TN3270_SCS_CTL_CODES,   "SCS-CTL-CODES" },
438
  { TN3270_SYSREQ,          "SYSREQ" },
439
  { 0, NULL }
440
};
441
442
static void
443
dissect_tn3270e_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
444
                       int len, proto_tree *tree, proto_item *item _U_)
445
412
{
446
447
412
  uint8_t cmd;
448
412
  int    datalen;
449
412
  int    connect_offset = 0;
450
412
  int    device_type    = 0;
451
412
  int    rsn            = 0;
452
453
10.4k
  while (len > 0) {
454
10.0k
    cmd = tvb_get_uint8(tvb, offset);
455
10.0k
    proto_tree_add_item( tree, hf_tn3270_subopt, tvb, offset, 1, ENC_BIG_ENDIAN );
456
10.0k
    switch (cmd) {
457
164
      case TN3270_CONNECT:
458
164
            proto_tree_add_item( tree, hf_tn3270_connect, tvb, offset + 1, len, ENC_ASCII );
459
164
            offset += (len - 1);
460
164
            len -= (len - 1);
461
164
            break;
462
208
      case TN3270_IS:
463
208
            device_type = tvb_get_uint8(tvb, offset-1);
464
208
            if (device_type == TN3270_DEVICE_TYPE) {
465
                /* If there is a terminal type to display, then it will be followed by CONNECT */
466
1
                connect_offset = tvb_find_uint8(tvb, offset + 1, len, TN3270_CONNECT);
467
1
                if (connect_offset != -1) {
468
1
                  datalen = connect_offset - (offset + 1);
469
1
                  if (datalen > 0) {
470
1
                    proto_tree_add_item( tree, hf_tn3270_is, tvb, offset + 1, datalen, ENC_ASCII );
471
1
                    check_tn3270_model(pinfo, tvb_format_text(pinfo->pool, tvb, offset + 1, datalen));
472
1
                    offset += datalen;
473
1
                    len -= datalen;
474
1
                  }
475
1
                }
476
1
            }
477
208
            break;
478
36
      case TN3270_REASON:
479
36
            offset++;
480
36
            len--;
481
36
            proto_tree_add_item( tree, hf_tn3270_reason, tvb, offset, 1, ENC_BIG_ENDIAN );
482
36
            break;
483
399
      case TN3270_REQUEST:
484
399
            add_tn3270_conversation(pinfo, 1, 0);
485
399
            device_type = tvb_get_uint8(tvb, offset-1);
486
399
            if (device_type == TN3270_DEVICE_TYPE) {
487
33
              proto_tree_add_item( tree, hf_tn3270_request_string, tvb, offset + 1, len-1, ENC_ASCII );
488
33
              offset += (len - 1);
489
33
              len -= (len - 1);
490
366
            }else if (device_type == TN3270_FUNCTIONS) {
491
20
              while (len > 0) {
492
20
                rsn = tvb_get_uint8(tvb, offset);
493
20
                proto_tree_add_item( tree, hf_tn3270_request, tvb, offset, 1, ENC_BIG_ENDIAN );
494
20
                if (try_val_to_str(rsn, tn3270_request_vals) == NULL)
495
20
                    break;
496
497
0
                offset++;
498
0
                len--;
499
0
              }
500
20
            }
501
399
            break;
502
10.0k
    }
503
10.0k
    offset++;
504
10.0k
    len--;
505
10.0k
  }
506
507
412
}
508
509
static void
510
dissect_starttls_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
511
                       int len _U_, proto_tree *tree, proto_item *item _U_)
512
31
{
513
31
  telnet_conv_info_t *session = telnet_get_session(pinfo);
514
515
31
  proto_tree_add_item(tree, hf_telnet_starttls, tvb, offset, 1, ENC_BIG_ENDIAN);
516
517
31
  if (session->starttls_requested_in == 0) {
518
    /* First sender (client or server) requesting to start TLS. */
519
5
    session->starttls_requested_in = pinfo->num;
520
5
    session->starttls_port = pinfo->srcport;
521
26
  } else if (session->starttls_requested_in < pinfo->num &&
522
22
      session->starttls_port != pinfo->srcport) {
523
    /* Other side confirms that following data is TLS. */
524
0
    ssl_starttls_ack(tls_handle, pinfo, telnet_handle);
525
0
  }
526
31
}
527
528
static const value_string telnet_outmark_subopt_cmd_vals[] = {
529
  { '\x06', "ACK" },
530
  { '\x15', "NAK" },
531
  { 'D',    "Default" },
532
  { 'T',    "Top" },
533
  { 'B',    "Bottom" },
534
  { 'L',    "Left" },
535
  { 'R',    "Right" },
536
  { 0, NULL }
537
};
538
539
static void
540
dissect_outmark_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
541
                       int len, proto_tree *tree, proto_item *item _U_)
542
116
{
543
116
  int    gs_offset, datalen;
544
545
280
  while (len > 0) {
546
164
    proto_tree_add_item(tree, hf_telnet_outmark_subopt_cmd, tvb, offset, 1, ENC_ASCII);
547
548
164
    offset++;
549
164
    len--;
550
551
    /* Look for a GS */
552
164
    gs_offset = tvb_find_uint8(tvb, offset, len, 29);
553
164
    if (gs_offset == -1) {
554
      /* None found - run to the end of the packet. */
555
116
      gs_offset = offset + len;
556
116
    }
557
164
    datalen = gs_offset - offset;
558
164
    if (datalen > 0) {
559
81
      proto_tree_add_item(tree, hf_telnet_outmark_subopt_banner, tvb, offset, datalen, ENC_ASCII);
560
81
      offset += datalen;
561
81
      len -= datalen;
562
81
    }
563
164
  }
564
116
}
565
566
static void
567
dissect_htstops_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, int offset, int len,
568
                       proto_tree *tree, proto_item *item)
569
129
{
570
129
  uint8_t cmd;
571
129
  uint8_t tabval;
572
573
129
  cmd = tvb_get_uint8(tvb, offset);
574
129
  switch (cmd) {
575
576
50
  case 0:       /* IS */
577
50
    proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Here's my %s", optname);
578
50
    offset++;
579
50
    len--;
580
50
    break;
581
582
16
  case 1:       /* SEND */
583
16
    proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Send your %s", optname);
584
16
    offset++;
585
16
    len--;
586
16
    break;
587
588
63
  default:
589
63
    expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
590
63
    offset++;
591
63
    len--;
592
63
    if (len > 0)
593
50
      proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
594
63
    return;
595
129
  }
596
597
4.60k
  while (len > 0) {
598
4.53k
    tabval = tvb_get_uint8(tvb, offset);
599
4.53k
    switch (tabval) {
600
601
1.24k
    case 0:
602
1.24k
      proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
603
1.24k
                          tabval, "Sender wants to handle tab stops");
604
1.24k
      break;
605
606
3.01k
    default:
607
3.01k
      proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
608
3.01k
                          tabval, "Sender wants receiver to handle tab stop at %u",
609
3.01k
                          tabval);
610
3.01k
      break;
611
612
36
    case 251:
613
55
    case 252:
614
56
    case 253:
615
82
    case 254:
616
82
      proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
617
82
                          tabval, "Invalid value: %u", tabval);
618
82
      break;
619
620
197
    case 255:
621
197
      proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
622
197
                          tabval, "Sender wants receiver to handle tab stops");
623
197
      break;
624
4.53k
    }
625
4.53k
    offset++;
626
4.53k
    len--;
627
4.53k
  }
628
66
}
629
630
static void
631
dissect_naws_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
632
                    int len _U_, proto_tree *tree, proto_item *item _U_)
633
0
{
634
0
  proto_tree_add_item(tree, hf_telnet_naws_subopt_width, tvb, offset, 2, ENC_BIG_ENDIAN);
635
0
  offset += 2;
636
0
  proto_tree_add_item(tree, hf_telnet_naws_subopt_height, tvb, offset, 2, ENC_BIG_ENDIAN);
637
0
}
638
639
/* BEGIN RFC-2217 (COM Port Control) Definitions */
640
641
8
#define TNCOMPORT_SIGNATURE             0
642
12
#define TNCOMPORT_SETBAUDRATE           1
643
121
#define TNCOMPORT_SETDATASIZE           2
644
55
#define TNCOMPORT_SETPARITY             3
645
4
#define TNCOMPORT_SETSTOPSIZE           4
646
17
#define TNCOMPORT_SETCONTROL            5
647
11
#define TNCOMPORT_NOTIFYLINESTATE       6
648
160
#define TNCOMPORT_NOTIFYMODEMSTATE      7
649
15
#define TNCOMPORT_FLOWCONTROLSUSPEND    8
650
4
#define TNCOMPORT_FLOWCONTROLRESUME      9
651
31
#define TNCOMPORT_SETLINESTATEMASK      10
652
461
#define TNCOMPORT_SETMODEMSTATEMASK     11
653
0
#define TNCOMPORT_PURGEDATA             12
654
655
/* END RFC-2217 (COM Port Control) Definitions */
656
657
static void
658
dissect_comport_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, int offset, int len,
659
                       proto_tree *tree, proto_item *item)
660
588
{
661
588
  static const char *datasizes[] = {
662
588
    "Request",
663
588
    "<invalid>",
664
588
    "<invalid>",
665
588
    "<invalid>",
666
588
    "<invalid>",
667
588
    "5",
668
588
    "6",
669
588
    "7",
670
588
    "8"
671
588
  };
672
588
  static const char *parities[] = {
673
588
    "Request",
674
588
    "None",
675
588
    "Odd",
676
588
    "Even",
677
588
    "Mark",
678
588
    "Space"
679
588
  };
680
588
  static const char *stops[] = {
681
588
    "Request",
682
588
    "1",
683
588
    "2",
684
588
    "1.5"
685
588
  };
686
588
  static const char *control[] = {
687
588
    "Output Flow Control Request",
688
588
    "Output Flow: None",
689
588
    "Output Flow: XON/XOFF",
690
588
    "Output Flow: CTS/RTS",
691
588
    "Break Request",
692
588
    "Break: ON",
693
588
    "Break: OFF",
694
588
    "DTR Request",
695
588
    "DTR: ON",
696
588
    "DTR: OFF",
697
588
    "RTS Request",
698
588
    "RTS: ON",
699
588
    "RTS: OFF",
700
588
    "Input Flow Control Request",
701
588
    "Input Flow: None",
702
588
    "Input Flow: XON/XOFF",
703
588
    "Input Flow: CTS/RTS",
704
588
    "Output Flow: DCD",
705
588
    "Input Flow: DTR",
706
588
    "Output Flow: DSR"
707
588
  };
708
588
  static const char *linestate_bits[] = {
709
588
    "Data Ready",
710
588
    "Overrun Error",
711
588
    "Parity Error",
712
588
    "Framing Error",
713
588
    "Break Detected",
714
588
    "Transfer Holding Register Empty",
715
588
    "Transfer Shift Register Empty",
716
588
    "Timeout Error"
717
588
  };
718
588
  static const char *modemstate_bits[] = {
719
588
    "DCTS",
720
588
    "DDSR",
721
588
    "TERI",
722
588
    "DDCD",
723
588
    "CTS",
724
588
    "DSR",
725
588
    "RI",
726
588
    "DCD"
727
588
  };
728
588
  static const char *purges[] = {
729
588
    "Purge None",
730
588
    "Purge RX",
731
588
    "Purge TX",
732
588
    "Purge RX/TX"
733
588
  };
734
735
588
  uint8_t cmd;
736
588
  uint8_t isservercmd;
737
588
  const char *source;
738
739
588
  cmd = tvb_get_uint8(tvb, offset);
740
588
  isservercmd = cmd > 99;
741
588
  cmd = (isservercmd) ? (cmd - 100) : cmd;
742
588
  source = (isservercmd) ? "Server" : "Client";
743
588
  switch (cmd) {
744
8
  case TNCOMPORT_SIGNATURE:
745
8
    len--;
746
8
    if (len == 0) {
747
0
      proto_tree_add_string_format(tree, hf_telnet_comport_subopt_signature, tvb, offset, 1, "", "%s Requests Signature", source);
748
8
    } else {
749
8
      char *sig = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset + 1, len, ENC_ASCII);
750
8
      proto_tree_add_string_format(tree, hf_telnet_comport_subopt_signature, tvb, offset, 1 + len, sig,
751
8
                                         "%s Signature: %s",source, sig);
752
8
    }
753
8
    break;
754
755
12
  case TNCOMPORT_SETBAUDRATE:
756
12
    len--;
757
12
    if (len >= 4) {
758
11
      uint32_t baud = tvb_get_ntohl(tvb, offset+1);
759
11
      if (baud == 0) {
760
10
        proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_baud_rate, tvb, offset, 5, 0, "%s Requests Baud Rate",source);
761
10
      } else {
762
1
        proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_baud_rate, tvb, offset, 5, baud, "%s Baud Rate: %d",source,baud);
763
1
      }
764
11
    } else {
765
1
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_baud_rate, "%s <Invalid Baud Rate Packet>", source);
766
1
    }
767
12
    break;
768
769
121
  case TNCOMPORT_SETDATASIZE:
770
121
    len--;
771
121
    if (len >= 1) {
772
29
      uint8_t datasize = tvb_get_uint8(tvb, offset+1);
773
29
      const char *ds = (datasize > 8) ? "<invalid>" : datasizes[datasize];
774
29
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_data_size, tvb, offset, 2, datasize,
775
29
                                       "%s Data Size: %s",source,ds);
776
92
    } else {
777
92
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_data_size, "%s <Invalid Data Size Packet>", source);
778
92
    }
779
121
    break;
780
781
55
  case TNCOMPORT_SETPARITY:
782
55
    len--;
783
55
    if (len >= 1) {
784
55
      uint8_t parity = tvb_get_uint8(tvb, offset+1);
785
55
      const char *pr = (parity > 5) ? "<invalid>" : parities[parity];
786
55
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_parity, tvb, offset, 2, parity,
787
55
                                       "%s Parity: %s",source,pr);
788
55
    } else {
789
0
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_parity, "%s <Invalid Parity Packet>", source);
790
0
    }
791
55
    break;
792
4
  case TNCOMPORT_SETSTOPSIZE:
793
4
    len--;
794
4
    if (len >= 1) {
795
4
      uint8_t stop = tvb_get_uint8(tvb, offset+1);
796
4
      const char *st = (stop > 3) ? "<invalid>" : stops[stop];
797
4
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_stop, tvb, offset, 2, stop,
798
4
                                       "%s Stop: %s",source,st);
799
4
    } else {
800
0
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_stop, "%s <Invalid Stop Packet>", source);
801
0
    }
802
4
    break;
803
804
17
  case TNCOMPORT_SETCONTROL:
805
17
    len--;
806
17
    if (len >= 1) {
807
16
      uint8_t crt = tvb_get_uint8(tvb, offset+1);
808
16
      const char *c = (crt > 19) ? "Control: <invalid>" : control[crt];
809
16
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_control, tvb, offset, 2, crt,
810
16
                                       "%s Stop: %s",source,c);
811
16
    } else {
812
1
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_control, "%s <Invalid Control Packet>", source);
813
1
    }
814
17
    break;
815
816
10
  case TNCOMPORT_SETLINESTATEMASK:
817
11
  case TNCOMPORT_NOTIFYLINESTATE:
818
11
    len--;
819
11
    if (len >= 1) {
820
10
      const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
821
10
        "%s Set Linestate Mask: %s" : "%s Linestate: %s";
822
10
      int hf_line = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
823
10
        hf_telnet_comport_set_linestate_mask : hf_telnet_comport_linestate;
824
10
      char ls_buffer[512];
825
10
      uint8_t ls = tvb_get_uint8(tvb, offset+1);
826
10
      int print_count = 0;
827
10
      int idx;
828
10
      ls_buffer[0] = '\0';
829
90
      for (idx = 0; idx < 8; idx++) {
830
80
        int bit = ls & 1;
831
80
        if (bit) {
832
23
          if (print_count != 0) {
833
13
            (void) g_strlcat(ls_buffer,", ",512);
834
13
          }
835
23
          (void) g_strlcat(ls_buffer,linestate_bits[idx], 512);
836
23
          print_count++;
837
23
        }
838
80
        ls = ls >> 1;
839
80
      }
840
10
      proto_tree_add_string_format(tree, hf_line, tvb, offset, 2, ls_buffer, print_pattern, source, ls_buffer);
841
10
    } else {
842
1
      const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
843
1
        "%s <Invalid Linestate Mask>" : "%s <Invalid Linestate Packet>";
844
1
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_linestate, print_pattern, source);
845
1
    }
846
11
    break;
847
848
144
  case TNCOMPORT_SETMODEMSTATEMASK:
849
160
  case TNCOMPORT_NOTIFYMODEMSTATE:
850
160
    len--;
851
160
    if (len >= 1) {
852
157
      const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
853
141
        "%s Set Modemstate Mask: %s" : "%s Modemstate: %s";
854
157
      int hf_modem = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
855
141
        hf_telnet_comport_set_modemstate_mask : hf_telnet_comport_modemstate;
856
157
      char ms_buffer[256];
857
157
      uint8_t ms = tvb_get_uint8(tvb, offset+1);
858
157
      int print_count = 0;
859
157
      int idx;
860
157
      ms_buffer[0] = '\0';
861
1.41k
      for (idx = 0; idx < 8; idx++) {
862
1.25k
        int bit = ms & 1;
863
1.25k
        if (bit) {
864
472
          if (print_count != 0) {
865
321
            (void) g_strlcat(ms_buffer,", ",256);
866
321
          }
867
472
          (void) g_strlcat(ms_buffer,modemstate_bits[idx],256);
868
472
          print_count++;
869
472
        }
870
1.25k
        ms = ms >> 1;
871
1.25k
      }
872
157
      proto_tree_add_string_format(tree, hf_modem, tvb, offset, 2, ms_buffer, print_pattern, source, ms_buffer);
873
157
    } else {
874
3
      const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
875
3
        "%s <Invalid Modemstate Mask>" : "%s <Invalid Modemstate Packet>";
876
3
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_modemstate, print_pattern, source);
877
3
    }
878
160
    break;
879
880
15
  case TNCOMPORT_FLOWCONTROLSUSPEND:
881
15
    len--;
882
15
    proto_tree_add_none_format(tree, hf_telnet_comport_subopt_flow_control_suspend, tvb, offset, 1, "%s Flow Control Suspend",source);
883
15
    break;
884
885
4
  case TNCOMPORT_FLOWCONTROLRESUME:
886
4
    len--;
887
4
    proto_tree_add_none_format(tree, hf_telnet_comport_subopt_flow_control_resume, tvb, offset, 1, "%s Flow Control Resume",source);
888
4
    break;
889
890
0
  case TNCOMPORT_PURGEDATA:
891
0
    len--;
892
0
    if (len >= 1) {
893
0
      uint8_t purge = tvb_get_uint8(tvb, offset+1);
894
0
      const char *p = (purge > 3) ? "<Purge invalid>" : purges[purge];
895
0
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_purge, tvb, offset, 2, purge,
896
0
                                       "%s %s",source,p);
897
0
    } else {
898
0
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_purge, "%s <Invalid Purge Packet>", source);
899
0
    }
900
0
    break;
901
902
181
  default:
903
181
    expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
904
181
    offset++;
905
181
    len--;
906
181
    if (len > 0)
907
154
      proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
908
181
    return;
909
588
  }
910
911
588
}
912
913
static const value_string rfc_opt_vals[] = {
914
  { 0, "OFF" },
915
  { 1, "ON" },
916
  { 2, "RESTART-ANY" },
917
  { 3, "RESTART-XON" },
918
  { 0, NULL }
919
};
920
921
static void
922
dissect_rfc_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
923
                   int len _U_, proto_tree *tree, proto_item *item _U_)
924
20
{
925
20
  proto_tree_add_item(tree, hf_telnet_rfc_subopt_cmd, tvb, offset, 1, ENC_BIG_ENDIAN);
926
20
}
927
928
2
#define TN_ENC_IS               0
929
11
#define TN_ENC_SUPPORT          1
930
2
#define TN_ENC_REPLY            2
931
0
#define TN_ENC_START            3
932
7
#define TN_ENC_END              4
933
0
#define TN_ENC_REQUEST_START    5
934
1
#define TN_ENC_REQUEST_END      6
935
0
#define TN_ENC_ENC_KEYID        7
936
0
#define TN_ENC_DEC_KEYID        8
937
static const value_string enc_cmd_vals[] = {
938
  { TN_ENC_IS,            "IS" },
939
  { TN_ENC_SUPPORT,       "SUPPORT" },
940
  { TN_ENC_REPLY,         "REPLY" },
941
  { TN_ENC_START,         "START" },
942
  { TN_ENC_END,           "END" },
943
  { TN_ENC_REQUEST_START, "REQUEST-START" },
944
  { TN_ENC_REQUEST_END,   "REQUEST-END" },
945
  { TN_ENC_ENC_KEYID,     "ENC_KEYID" },
946
  { TN_ENC_DEC_KEYID,     "DEC_KEYID" },
947
  { 0, NULL }
948
};
949
950
#define TN_ENCTYPE_NULL                 0
951
#define TN_ENCTYPE_DES_CFB64            1
952
#define TN_ENCTYPE_DES_OFB64            2
953
#define TN_ENCTYPE_DES3_CFB64           3
954
#define TN_ENCTYPE_DES3_OFB64           4
955
#define TN_ENCTYPE_CAST5_40_CFB64       8
956
#define TN_ENCTYPE_CAST5_40_OFB64       9
957
#define TN_ENCTYPE_CAST128_CFB64        10
958
#define TN_ENCTYPE_CAST128_OFB64        11
959
static const value_string enc_type_vals[] = {
960
  { TN_ENCTYPE_NULL,                  "NULL" },
961
  { TN_ENCTYPE_DES_CFB64,             "DES_CFB64" },
962
  { TN_ENCTYPE_DES_OFB64,             "DES_OFB64" },
963
  { TN_ENCTYPE_DES3_CFB64,            "DES3_CFB64" },
964
  { TN_ENCTYPE_DES3_OFB64,            "DES3_OFB64" },
965
  { TN_ENCTYPE_CAST5_40_CFB64,        "CAST5_40_CFB64" },
966
  { TN_ENCTYPE_CAST5_40_OFB64,        "CAST5_40_OFB64" },
967
  { TN_ENCTYPE_CAST128_CFB64,         "CAST128_CFB64" },
968
  { TN_ENCTYPE_CAST128_OFB64,         "CAST128_OFB64" },
969
  { 0, NULL }
970
};
971
972
973
32
#define TN_AC_IS        0
974
2
#define TN_AC_SEND      1
975
8
#define TN_AC_REPLY     2
976
0
#define TN_AC_NAME      3
977
static const value_string auth_cmd_vals[] = {
978
  { TN_AC_IS,     "IS" },
979
  { TN_AC_SEND,   "SEND" },
980
  { TN_AC_REPLY,  "REPLY" },
981
  { TN_AC_NAME,   "NAME" },
982
  { 0, NULL }
983
};
984
985
5
#define TN_AT_NULL           0
986
#define TN_AT_KRB4           1
987
4
#define TN_AT_KRB5           2
988
#define TN_AT_SPX            3
989
#define TN_AT_MINK           4
990
#define TN_AT_SRP            5
991
#define TN_AT_RSA            6
992
0
#define TN_AT_SSL            7
993
#define TN_AT_LOKI          10
994
#define TN_AT_SSA           11
995
#define TN_AT_KEA_SJ        12
996
#define TN_AT_KEA_SJ_INTEG  13
997
#define TN_AT_DSS           14
998
#define TN_AT_NTLM          15
999
static const value_string auth_type_vals[] = {
1000
  { TN_AT_NULL,         "NULL" },
1001
  { TN_AT_KRB4,         "Kerberos v4" },
1002
  { TN_AT_KRB5,         "Kerberos v5" },
1003
  { TN_AT_SPX,          "SPX" },
1004
  { TN_AT_MINK,         "MINK" },
1005
  { TN_AT_SRP,          "SRP" },
1006
  { TN_AT_RSA,          "RSA" },
1007
  { TN_AT_SSL,          "SSL" },
1008
  { TN_AT_LOKI,         "LOKI" },
1009
  { TN_AT_SSA,          "SSA" },
1010
  { TN_AT_KEA_SJ,       "KEA_SJ" },
1011
  { TN_AT_KEA_SJ_INTEG, "KEA_SJ_INTEG" },
1012
  { TN_AT_DSS,          "DSS" },
1013
  { TN_AT_NTLM,         "NTLM" },
1014
  { 0, NULL }
1015
};
1016
static const true_false_string auth_mod_cred_fwd = {
1017
  "Client WILL forward auth creds",
1018
  "Client will NOT forward auth creds"
1019
};
1020
static const true_false_string auth_mod_how = {
1021
  "Mutual authentication",
1022
  "One Way authentication"
1023
};
1024
#define TN_AM_OFF               0x00
1025
#define TN_AM_USING_TELOPT      0x01
1026
#define TN_AM_AFTER_EXCHANGE    0x02
1027
#define TN_AM_RESERVED          0x04
1028
static const value_string auth_mod_enc[] = {
1029
  { TN_AM_OFF,            "Off" },
1030
  { TN_AM_USING_TELOPT,   "Telnet Options" },
1031
  { TN_AM_AFTER_EXCHANGE, "After Exchange" },
1032
  { TN_AM_RESERVED,       "Reserved" },
1033
  { 0, NULL }
1034
};
1035
1
#define TN_KRB5_TYPE_AUTH               0
1036
#define TN_KRB5_TYPE_REJECT             1
1037
#define TN_KRB5_TYPE_ACCEPT             2
1038
3
#define TN_KRB5_TYPE_RESPONSE           3
1039
#define TN_KRB5_TYPE_FORWARD            4
1040
#define TN_KRB5_TYPE_FORWARD_ACCEPT     5
1041
#define TN_KRB5_TYPE_FORWARD_REJECT     6
1042
static const value_string auth_krb5_types[] = {
1043
  { TN_KRB5_TYPE_AUTH,            "Auth" },
1044
  { TN_KRB5_TYPE_REJECT,          "Reject" },
1045
  { TN_KRB5_TYPE_ACCEPT,          "Accept" },
1046
  { TN_KRB5_TYPE_RESPONSE,        "Response" },
1047
  { TN_KRB5_TYPE_FORWARD,         "Forward" },
1048
  { TN_KRB5_TYPE_FORWARD_ACCEPT,  "Forward Accept" },
1049
  { TN_KRB5_TYPE_FORWARD_REJECT,  "Forward Reject" },
1050
  { 0, NULL }
1051
};
1052
static void
1053
dissect_authentication_type_pair(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, proto_tree *tree)
1054
74
{
1055
74
  static int * const auth_mods[] = {
1056
74
    &hf_telnet_auth_mod_enc,
1057
74
    &hf_telnet_auth_mod_cred_fwd,
1058
74
    &hf_telnet_auth_mod_how,
1059
74
    &hf_telnet_auth_mod_who,
1060
74
    NULL
1061
74
  };
1062
1063
74
  proto_tree_add_item(tree, hf_telnet_auth_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1064
74
  proto_tree_add_bitmask_list(tree, tvb, offset+1, 1, auth_mods, ENC_BIG_ENDIAN);
1065
74
}
1066
1067
/* Assume no telnet option subnegotiation exceeds 10 kB (arbitrary limit). */
1068
549
#define MAX_TELNET_OPTION_SUBNEG_LEN 10240
1069
1070
static tvbuff_t *
1071
unescape_and_tvbuffify_telnet_option(packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
1072
549
{
1073
549
  tvbuff_t     *option_subneg_tvb;
1074
549
  uint8_t      *buf;
1075
549
  const uint8_t *spos;
1076
549
  uint8_t      *dpos;
1077
549
  int           skip, l;
1078
1079
549
  if(len >= MAX_TELNET_OPTION_SUBNEG_LEN)
1080
0
    return NULL;
1081
1082
549
  spos = tvb_get_ptr(tvb, offset, len);
1083
549
  const uint8_t *last_src_pos = spos + len - 1;
1084
549
  buf = (uint8_t *)wmem_alloc(pinfo->pool, len);
1085
549
  dpos = buf;
1086
549
  skip = 0;
1087
549
  l = len;
1088
16.1k
  while(l > 0) {
1089
    // XXX Add expert info if spos >= last_src_pos?
1090
15.6k
    if(spos < last_src_pos && (spos[0] == 0xff) && (spos[1] == 0xff)) {
1091
1.98k
      skip++;
1092
1.98k
      l -= 2;
1093
1.98k
      *(dpos++) = 0xff;
1094
1.98k
      spos += 2;
1095
1.98k
      continue;
1096
1.98k
    }
1097
13.6k
    *(dpos++) = *(spos++);
1098
13.6k
    l--;
1099
13.6k
  }
1100
549
  option_subneg_tvb = tvb_new_child_real_data(tvb, buf, len-skip, len-skip);
1101
549
  add_new_data_source(pinfo, option_subneg_tvb, "Unpacked Telnet Option");
1102
1103
549
  return option_subneg_tvb;
1104
549
}
1105
1106
1107
/* as per RFC2942 */
1108
static void
1109
dissect_krb5_authentication_data(packet_info *pinfo, tvbuff_t *tvb, int offset, int len, proto_tree *tree, uint8_t acmd)
1110
4
{
1111
4
  tvbuff_t *krb5_tvb;
1112
4
  uint8_t   krb5_cmd;
1113
1114
4
  krb5_cmd=tvb_get_uint8(tvb, offset);
1115
4
  proto_tree_add_uint(tree, hf_telnet_auth_krb5_type, tvb, offset, 1, krb5_cmd);
1116
4
  offset++;
1117
4
  len--;
1118
1119
1120
  /* IAC SB AUTHENTICATION IS <authentication-type-pair> AUTH <Kerberos V5 KRB_AP_REQ message> IAC SE */
1121
4
  if((acmd==TN_AC_IS)&&(krb5_cmd==TN_KRB5_TYPE_AUTH)){
1122
1
    if(len){
1123
0
      krb5_tvb=tvb_new_subset_length(tvb, offset, len);
1124
0
      dissect_kerberos_main(krb5_tvb, pinfo, tree, false, NULL);
1125
0
    }
1126
1
  }
1127
1128
1129
1130
  /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> ACCEPT IAC SE */
1131
  /* nothing more to dissect */
1132
1133
1134
1135
  /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> REJECT <optional reason for rejection> IAC SE*/
1136
/*qqq*/
1137
1138
1139
  /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> RESPONSE <KRB_AP_REP message> IAC SE */
1140
4
  if((acmd==TN_AC_REPLY)&&(krb5_cmd==TN_KRB5_TYPE_RESPONSE)){
1141
0
    if(len){
1142
0
      krb5_tvb=tvb_new_subset_length(tvb, offset, len);
1143
0
      dissect_kerberos_main(krb5_tvb, pinfo, tree, false, NULL);
1144
0
    }
1145
0
  }
1146
1147
1148
  /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD <KRB_CRED message> IAC SE */
1149
  /* XXX unclear what this one looks like */
1150
1151
1152
  /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_ACCEPT IAC SE */
1153
  /* nothing more to dissect */
1154
1155
1156
1157
  /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_REJECT */
1158
  /* nothing more to dissect */
1159
4
}
1160
1161
1162
#define TN_AUTH_SSL_START  1
1163
0
#define TN_AUTH_SSL_ACCEPT 2
1164
#define TN_AUTH_SSL_REJECT 3
1165
1166
static const value_string ssl_auth_status[] = {
1167
  { TN_AUTH_SSL_START,  "Start" },
1168
  { TN_AUTH_SSL_ACCEPT, "Accepted" },
1169
  { TN_AUTH_SSL_REJECT, "Rejected" },
1170
  { 0, NULL }
1171
};
1172
1173
static void
1174
dissect_ssl_authentication_data(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree, uint8_t acmd)
1175
0
{
1176
0
  unsigned ssl_status;
1177
1178
0
  proto_tree_add_item_ret_uint(tree, hf_telnet_auth_ssl_status, tvb, offset, 1, ENC_NA, &ssl_status);
1179
1180
0
  if (acmd == TN_AC_REPLY && ssl_status == TN_AUTH_SSL_ACCEPT)
1181
    /* TLS negotiation will immediately follow this packet. */
1182
0
    ssl_starttls_ack(tls_handle, pinfo, telnet_handle);
1183
0
}
1184
1185
/* as per RFC2941 */
1186
static void
1187
dissect_authentication_data(packet_info *pinfo, tvbuff_t *tvb, int offset, int len, proto_tree *tree, uint8_t acmd)
1188
28
{
1189
28
  uint8_t auth_type;
1190
1191
28
  dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1192
28
  auth_type = tvb_get_uint8(tvb, offset);
1193
28
  offset += 2;
1194
28
  len -= 2;
1195
1196
28
  switch (auth_type) {
1197
5
  case TN_AT_NULL:
1198
5
    break;
1199
1200
0
  case TN_AT_SSL:
1201
0
    dissect_ssl_authentication_data(pinfo, tvb, offset, tree, acmd);
1202
0
    break;
1203
1204
4
  case TN_AT_KRB5:
1205
4
    dissect_krb5_authentication_data(pinfo, tvb, offset, len, tree, acmd);
1206
4
    break;
1207
1208
19
  default:
1209
    /* We don't (yet) know how to dissect the data for this authentication type. */
1210
19
    if (len > 0)
1211
12
      proto_tree_add_bytes_format(tree, hf_telnet_auth_data, tvb, offset, len, NULL, "Unhandled authentication data");
1212
28
  }
1213
28
}
1214
1215
static void
1216
dissect_authentication_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, int offset, int len,
1217
                              proto_tree *tree, proto_item *item _U_)
1218
62
{
1219
62
  uint8_t acmd;
1220
1221
62
  acmd=tvb_get_uint8(tvb, offset);
1222
62
  proto_tree_add_uint(tree, hf_telnet_auth_cmd, tvb, offset, 1, acmd);
1223
62
  offset++;
1224
62
  len--;
1225
1226
62
  switch(acmd){
1227
4
  case TN_AC_REPLY:
1228
28
  case TN_AC_IS:
1229
28
    dissect_authentication_data(pinfo, tvb, offset, len, tree, acmd);
1230
28
    break;
1231
1232
2
  case TN_AC_SEND:
1233
48
    while(len>0){
1234
46
      dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1235
46
      offset+=2;
1236
46
      len-=2;
1237
46
    }
1238
2
    break;
1239
1240
0
  case TN_AC_NAME:
1241
0
    proto_tree_add_item(tree, hf_telnet_auth_name, tvb, offset, len, ENC_ASCII);
1242
0
    break;
1243
62
  }
1244
62
}
1245
1246
/* This function only uses the octet in the buffer at 'offset' */
1247
308
static void dissect_encryption_type(tvbuff_t *tvb, int offset, proto_tree *tree) {
1248
308
  uint8_t etype;
1249
308
  etype = tvb_get_uint8(tvb, offset);
1250
308
  proto_tree_add_uint(tree, hf_telnet_enc_type, tvb, offset, 1, etype);
1251
308
}
1252
1253
static void
1254
dissect_encryption_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, int offset, int len,
1255
                          proto_tree *tree, proto_item *item)
1256
38
{
1257
38
  uint8_t ecmd, key_first_octet;
1258
1259
38
  ecmd = tvb_get_uint8(tvb, offset);
1260
38
  proto_tree_add_uint(tree, hf_telnet_enc_cmd, tvb, offset, 1, ecmd);
1261
1262
38
  offset++;
1263
38
  len--;
1264
1265
38
  switch(ecmd) {
1266
2
  case TN_ENC_IS:
1267
2
  case TN_ENC_REPLY:
1268
    /* encryption type, type-specific data ... */
1269
2
    if (len > 0) {
1270
2
      dissect_encryption_type(tvb, offset, tree);
1271
2
      offset++;
1272
2
      len--;
1273
2
      proto_tree_add_item(tree, hf_telnet_enc_type_data, tvb, offset, len, ENC_NA);
1274
2
    }
1275
2
    break;
1276
1277
11
  case TN_ENC_SUPPORT:
1278
    /* list of encryption types ... */
1279
317
    while (len > 0) {
1280
306
      dissect_encryption_type(tvb, offset, tree);
1281
306
      offset++;
1282
306
      len--;
1283
306
    }
1284
11
    break;
1285
1286
0
  case TN_ENC_START:
1287
    /* keyid ... */
1288
0
    if (len > 0) {
1289
0
      key_first_octet = tvb_get_uint8(tvb, offset);
1290
0
      proto_tree_add_bytes_format(tree, hf_telnet_enc_key_id, tvb, offset, len, NULL, (key_first_octet == 0) ? "Default key" : "Key ID");
1291
0
    }
1292
0
    break;
1293
1294
7
  case TN_ENC_END:
1295
    /* no data */
1296
7
    break;
1297
1298
0
  case TN_ENC_REQUEST_START:
1299
    /* (optional) keyid */
1300
0
    if (len > 0)
1301
0
      proto_tree_add_bytes_format(tree, hf_telnet_enc_key_id, tvb, offset, len, NULL, "Key ID (advisory)");
1302
0
    break;
1303
1304
1
  case TN_ENC_REQUEST_END:
1305
    /* no data */
1306
1
    break;
1307
1308
0
  case TN_ENC_ENC_KEYID:
1309
0
  case TN_ENC_DEC_KEYID:
1310
    /* (optional) keyid - if not supplied, there are no more known keys */
1311
0
    if (len > 0)
1312
0
      proto_tree_add_item(tree, hf_telnet_enc_key_id, tvb, offset, len, ENC_NA);
1313
0
    break;
1314
1315
17
  default:
1316
17
    expert_add_info(pinfo, item, &ei_telnet_enc_cmd_unknown);
1317
38
  }
1318
38
}
1319
1320
1.48k
#define VMWARE_TELNET_EXT 232
1321
1322
/* Option Subnegotiation */
1323
24
#define VMWARE_KNOWN_SUBOPTIONS_1 0
1324
52
#define VMWARE_KNOWN_SUBOPTIONS_2 1
1325
1326
/* Unknown Command Response */
1327
0
#define VMWARE_UNKNOWN_SUBOPTION_RCVD_1 2
1328
38
#define VMWARE_UNKNOWN_SUBOPTION_RCVD_2 3
1329
1330
/* vMotion Notification */
1331
3
#define VMWARE_VMOTION_BEGIN 40
1332
12
#define VMWARE_VMOTION_GOAHEAD 41
1333
3
#define VMWARE_VMOTION_NOTNOW 43
1334
12
#define VMWARE_VMOTION_PEER 44
1335
3
#define VMWARE_VMOTION_PEER_OK 45
1336
3
#define VMWARE_VMOTION_COMPLETE 46
1337
0
#define VMWARE_VMOTION_ABORT 48
1338
1339
/* Proxy operation */
1340
0
#define VMWARE_DO_PROXY 70
1341
0
#define VMWARE_WILL_PROXY 71
1342
0
#define VMWARE_WONT_PROXY 73
1343
1344
/* Virtual machine identification */
1345
0
#define VMWARE_VM_VC_UUID 80
1346
0
#define VMWARE_GET_VM_VC_UUID 81
1347
0
#define VMWARE_VM_NAME 82
1348
0
#define VMWARE_GET_VM_NAME 83
1349
0
#define VMWARE_VM_BIOS_UUID 84
1350
0
#define VMWARE_GET_VM_BIOS_UUID 85
1351
0
#define VMWARE_VM_LOCATION_UUID 86
1352
0
#define VMWARE_GET_VM_LOCATION_UUID 87
1353
1354
static const value_string vmware_cmd_vals[] = {
1355
  { VMWARE_KNOWN_SUBOPTIONS_1,       "KNOWN-SUBOPTIONS-1" },
1356
  { VMWARE_KNOWN_SUBOPTIONS_2,       "KNOWN-SUBOPTIONS-2" },
1357
  { VMWARE_UNKNOWN_SUBOPTION_RCVD_1, "UNKNOWN-SUBOPTION-RCVD-1" },
1358
  { VMWARE_UNKNOWN_SUBOPTION_RCVD_2, "UNKNOWN-SUBOPTION-RCVD-2" },
1359
  { VMWARE_VMOTION_BEGIN,            "VMOTION-BEGIN" },
1360
  { VMWARE_VMOTION_GOAHEAD,          "VMOTION-GOAHEAD" },
1361
  { VMWARE_VMOTION_NOTNOW,           "VMOTION-NOTNOW" },
1362
  { VMWARE_VMOTION_PEER,             "VMOTION-PEER" },
1363
  { VMWARE_VMOTION_PEER_OK,          "VMOTION-PEER-OK" },
1364
  { VMWARE_VMOTION_COMPLETE,         "VMOTION-COMPLETE" },
1365
  { VMWARE_VMOTION_ABORT,            "VMOTION-ABORT" },
1366
  { VMWARE_DO_PROXY,                 "DO-PROXY" },
1367
  { VMWARE_WILL_PROXY,               "WILL-PROXY" },
1368
  { VMWARE_WONT_PROXY,               "WONT-PROXY" },
1369
  { VMWARE_VM_VC_UUID,               "VM-VC-UUID" },
1370
  { VMWARE_GET_VM_VC_UUID,           "GET-VM-VC-UUID" },
1371
  { VMWARE_VM_NAME,                  "VM-NAME" },
1372
  { VMWARE_GET_VM_NAME,              "GET-VM-NAME" },
1373
  { VMWARE_VM_BIOS_UUID,             "VM-BIOS-UUID" },
1374
  { VMWARE_GET_VM_BIOS_UUID,         "GET-VM-BIOS-UUID" },
1375
  { VMWARE_VM_LOCATION_UUID,         "VM-LOCATION-UUID" },
1376
  { VMWARE_GET_VM_LOCATION_UUID,     "GET-VM-LOCATION-UUID" },
1377
  { 0, NULL }
1378
};
1379
1380
/* Encoding for the "direction" argument to DO-PROXY: */
1381
#define VMWARE_PROXY_DIRECTION_CLIENT 'C'
1382
#define VMWARE_PROXY_DIRECTION_SERVER 'S'
1383
1384
static const value_string vmware_proxy_direction_vals[] = {
1385
  { VMWARE_PROXY_DIRECTION_CLIENT, "Client" },
1386
  { VMWARE_PROXY_DIRECTION_SERVER, "Server" },
1387
  { 0, NULL }
1388
};
1389
1390
static void
1391
dissect_vmware_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset, int len,
1392
                      proto_tree *tree, proto_item *item _U_)
1393
146
{
1394
  /*
1395
   * The VMware virtual serial port proxy uses the Telnet protocol over TCP
1396
   * port 13370.  Use "Decode As..." or specify "-d tcp.port==13370,telnet" on
1397
   * the command-line.
1398
   */
1399
1400
146
  uint8_t vmwcmd;
1401
1402
146
  vmwcmd = tvb_get_uint8(tvb, offset);
1403
146
  proto_tree_add_uint(tree, hf_telnet_vmware_cmd, tvb, offset, 1, vmwcmd);
1404
146
  offset++;
1405
146
  len--;
1406
1407
146
  switch (vmwcmd) {
1408
1409
  /* --- Option Subnegotiation --- */
1410
1411
24
  case VMWARE_KNOWN_SUBOPTIONS_1:
1412
52
  case VMWARE_KNOWN_SUBOPTIONS_2:
1413
    /* Data: suboptions... */
1414
1.30k
    while (len > 0) {
1415
1.25k
      proto_tree_add_item(tree, hf_telnet_vmware_known_suboption_code, tvb, offset, 1, ENC_NA);
1416
1.25k
      offset++;
1417
1.25k
      len--;
1418
1.25k
    }
1419
52
    break;
1420
1421
  /* --- Unknown Command Response --- */
1422
1423
0
  case VMWARE_UNKNOWN_SUBOPTION_RCVD_1:
1424
38
  case VMWARE_UNKNOWN_SUBOPTION_RCVD_2:
1425
    /* Data: suboption */
1426
38
    proto_tree_add_item(tree, hf_telnet_vmware_unknown_subopt_code, tvb, offset, 1, ENC_NA);
1427
38
    offset++;
1428
38
    len--;
1429
38
    break;
1430
1431
  /* --- vMotion Notification --- */
1432
1433
3
  case VMWARE_VMOTION_BEGIN:
1434
3
  case VMWARE_VMOTION_NOTNOW:
1435
3
  case VMWARE_VMOTION_PEER_OK:
1436
3
  case VMWARE_VMOTION_COMPLETE: {
1437
    /* Data: sequence */
1438
3
    telnet_conv_info_t *session = telnet_get_session(pinfo);
1439
3
    if (session->vmotion_sequence_len < 0) {
1440
      /*
1441
       * There is nothing which _requires_ that the sequence length be constant
1442
       * throughout a Telnet conversation, but all implementations currently
1443
       * behave that way and here we assume it will be so.  If that changes,
1444
       * subsequent VMOTION-GOAHEAD/VMOTION-PEER messages might be incorrectly
1445
       * dissected, with bytes incorrectly assigned to the sequence or secret
1446
       * fields.  This should not be a big deal.
1447
       */
1448
2
      session->vmotion_sequence_len = len;
1449
2
    }
1450
3
    proto_tree_add_item(tree, hf_telnet_vmware_vmotion_sequence, tvb, offset, len, ENC_NA);
1451
3
    offset += len;
1452
3
    len = 0;
1453
3
  }
1454
3
    break;
1455
1456
4
  case VMWARE_VMOTION_GOAHEAD:
1457
4
  case VMWARE_VMOTION_PEER: {
1458
    /* Data: sequence secret */
1459
4
    telnet_conv_info_t *session = telnet_get_session(pinfo);
1460
1461
    /*
1462
     * The lack of delimiter between "sequence" and "secret" makes dissection
1463
     * challenging.  We need to track the "vMotion conversation", which spans
1464
     * two Telnet conversations with different endpoints.  The vMotion
1465
     * conversation is identified by a blob containing the concatenation of the
1466
     * sequence and secret.
1467
     */
1468
4
    if ((vmwcmd == VMWARE_VMOTION_GOAHEAD && session->vmotion_sequence_len >= 0) ||
1469
4
        (vmwcmd == VMWARE_VMOTION_PEER && session->vmotion_sequence_len < 0)) {
1470
0
      conversation_element_t conv_key[2] = {
1471
0
        {
1472
0
          .type = CE_BLOB,
1473
0
          .blob = {
1474
0
             .val = tvb_memdup(pinfo->pool, tvb, offset, len),
1475
0
             .len = len,
1476
0
          },
1477
0
        },
1478
0
        {
1479
0
          .type = CE_CONVERSATION_TYPE,
1480
0
          .conversation_type_val = CONVERSATION_VSPC_VMOTION,
1481
0
        }
1482
0
      };
1483
0
      conversation_t *vmotion_conv = find_conversation_full(pinfo->num, conv_key);
1484
1485
0
      if (vmwcmd == VMWARE_VMOTION_GOAHEAD && vmotion_conv == NULL) {
1486
        /*
1487
         * We have the full sequence and secret and we know the length of the
1488
         * "sequence" field.  Stash it (or, really, its session) where we can
1489
         * find it later.
1490
         */
1491
0
        vmotion_conv = conversation_new_full(pinfo->num, conv_key);
1492
0
        conversation_add_proto_data(vmotion_conv, proto_telnet, session);
1493
0
      } else if (vmwcmd == VMWARE_VMOTION_PEER && vmotion_conv != NULL) {
1494
        /*
1495
         * Try to find the length of the "sequence" field from the conversation
1496
         * containing the VMOTION-GOAHEAD message.
1497
         */
1498
0
        telnet_conv_info_t const *source_session =
1499
0
          (telnet_conv_info_t const *)conversation_get_proto_data(vmotion_conv, proto_telnet);
1500
1501
0
        if (source_session != NULL) {
1502
0
          session->vmotion_sequence_len = source_session->vmotion_sequence_len;
1503
0
        }
1504
        /* The secret is only used once, so the vMotion conversation ends here. */
1505
0
        vmotion_conv->last_frame = pinfo->num;
1506
0
      }
1507
0
      wmem_free(pinfo->pool, (void *)conv_key[0].blob.val);
1508
0
    }
1509
4
    if (session->vmotion_sequence_len >= 0 && session->vmotion_sequence_len <= len) {
1510
0
      proto_tree_add_item(tree, hf_telnet_vmware_vmotion_sequence, tvb, offset, (int)session->vmotion_sequence_len, ENC_NA);
1511
0
      offset += (int)session->vmotion_sequence_len;
1512
0
      len -= (int)session->vmotion_sequence_len;
1513
1514
0
      proto_tree_add_item(tree, hf_telnet_vmware_vmotion_secret, tvb, offset, len, ENC_NA);
1515
0
      offset += len;
1516
0
      len = 0;
1517
4
    } else {
1518
      /*
1519
       * With no delimiter between "sequence" and "secret", nor any other way
1520
       * of determining the lengths of those fields, we lack the information to
1521
       * be able to dissect this.  Skip it.
1522
       */
1523
4
      offset += len;
1524
4
      len = 0;
1525
4
    }
1526
4
  }
1527
4
    break;
1528
1529
0
  case VMWARE_VMOTION_ABORT:
1530
    /* no data */
1531
0
    break;
1532
1533
  /* --- Proxy Operation --- */
1534
1535
0
  case VMWARE_DO_PROXY:
1536
    /* Data: direction serviceUri */
1537
0
    proto_tree_add_item(tree, hf_telnet_vmware_proxy_direction, tvb, offset, 1, ENC_ASCII);
1538
0
    offset++;
1539
0
    len--;
1540
0
    proto_tree_add_item(tree, hf_telnet_vmware_proxy_serviceUri, tvb, offset, len, ENC_UTF_8);
1541
0
    offset += len;
1542
0
    len = 0;
1543
0
    break;
1544
1545
0
  case VMWARE_WILL_PROXY:
1546
0
  case VMWARE_WONT_PROXY:
1547
    /* no data */
1548
0
    break;
1549
1550
  /* --- Virtual Machine Identification --- */
1551
1552
0
  case VMWARE_GET_VM_VC_UUID:
1553
0
  case VMWARE_GET_VM_NAME:
1554
0
  case VMWARE_GET_VM_BIOS_UUID:
1555
0
  case VMWARE_GET_VM_LOCATION_UUID:
1556
    /* no data */
1557
0
    break;
1558
1559
0
  case VMWARE_VM_NAME:
1560
    /* Data: vm-name */
1561
0
    proto_tree_add_item(tree, hf_telnet_vmware_vm_name, tvb, offset, len, ENC_UTF_8);
1562
0
    offset += len;
1563
0
    len = 0;
1564
0
    break;
1565
1566
0
  case VMWARE_VM_VC_UUID:
1567
    /* Data: vm-uuid */
1568
0
    proto_tree_add_item(tree, hf_telnet_vmware_vm_vc_uuid, tvb, offset, len, ENC_ASCII);
1569
0
    offset += len;
1570
0
    len = 0;
1571
0
    break;
1572
1573
0
  case VMWARE_VM_BIOS_UUID:
1574
    /* Data: vm-uuid */
1575
0
    proto_tree_add_item(tree, hf_telnet_vmware_vm_bios_uuid, tvb, offset, len, ENC_ASCII);
1576
0
    offset += len;
1577
0
    len = 0;
1578
0
    break;
1579
1580
0
  case VMWARE_VM_LOCATION_UUID:
1581
    /* Data: vm-uuid */
1582
0
    proto_tree_add_item(tree, hf_telnet_vmware_vm_location_uuid, tvb, offset, len, ENC_ASCII);
1583
0
    offset += len;
1584
0
    len = 0;
1585
0
    break;
1586
1587
49
  default:
1588
49
    expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, vmwcmd);
1589
49
    if (len > 0)
1590
41
      proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
1591
49
    return;
1592
146
  }
1593
97
  if (len > 0) {
1594
24
    proto_item *pi = proto_tree_add_bytes_format(tree, hf_telnet_subcommand_data, tvb, offset, len, NULL, "Unexpected data");
1595
24
    expert_add_info_format(pinfo, pi, &ei_telnet_vmware_unexp_data, "%u bytes unexpected data", len);
1596
24
  }
1597
97
}
1598
1599
static const tn_opt options[] = {
1600
  {
1601
    "Binary Transmission",                      /* RFC 856 */
1602
    NULL,                                       /* no suboption negotiation */
1603
    NO_LENGTH,
1604
    0,
1605
    NULL
1606
  },
1607
  {
1608
    "Echo",                                     /* RFC 857 */
1609
    NULL,                                       /* no suboption negotiation */
1610
    NO_LENGTH,
1611
    0,
1612
    NULL
1613
  },
1614
  {
1615
    "Reconnection",                             /* DOD Protocol Handbook */
1616
    NULL,
1617
    NO_LENGTH,
1618
    0,
1619
    NULL
1620
  },
1621
  {
1622
    "Suppress Go Ahead",                        /* RFC 858 */
1623
    NULL,                                       /* no suboption negotiation */
1624
    NO_LENGTH,
1625
    0,
1626
    NULL
1627
  },
1628
  {
1629
    "Approx Message Size Negotiation",          /* Ethernet spec(!) */
1630
    NULL,
1631
    NO_LENGTH,
1632
    0,
1633
    NULL
1634
  },
1635
  {
1636
    "Status",                                   /* RFC 859 */
1637
    &ett_status_subopt,
1638
    VARIABLE_LENGTH,
1639
    1,
1640
    NULL                                        /* XXX - fill me in */
1641
  },
1642
  {
1643
    "Timing Mark",                              /* RFC 860 */
1644
    NULL,                                       /* no suboption negotiation */
1645
    NO_LENGTH,
1646
    0,
1647
    NULL
1648
  },
1649
  {
1650
    "Remote Controlled Trans and Echo",         /* RFC 726 */
1651
    &ett_rcte_subopt,
1652
    VARIABLE_LENGTH,
1653
    1,
1654
    NULL                                        /* XXX - fill me in */
1655
  },
1656
  {
1657
    "Output Line Width",                        /* DOD Protocol Handbook */
1658
    &ett_olw_subopt,
1659
    VARIABLE_LENGTH,                            /* XXX - fill me in */
1660
    0,                                          /* XXX - fill me in */
1661
    NULL                                        /* XXX - fill me in */
1662
  },
1663
  {
1664
    "Output Page Size",                         /* DOD Protocol Handbook */
1665
    &ett_ops_subopt,
1666
    VARIABLE_LENGTH,                            /* XXX - fill me in */
1667
    0,                                          /* XXX - fill me in */
1668
    NULL                                        /* XXX - fill me in */
1669
  },
1670
  {
1671
    "Output Carriage-Return Disposition",       /* RFC 652 */
1672
    &ett_crdisp_subopt,
1673
    FIXED_LENGTH,
1674
    2,
1675
    NULL                                        /* XXX - fill me in */
1676
  },
1677
  {
1678
    "Output Horizontal Tab Stops",              /* RFC 653 */
1679
    &ett_htstops_subopt,
1680
    VARIABLE_LENGTH,
1681
    1,
1682
    dissect_htstops_subopt
1683
  },
1684
  {
1685
    "Output Horizontal Tab Disposition",        /* RFC 654 */
1686
    &ett_htdisp_subopt,
1687
    FIXED_LENGTH,
1688
    2,
1689
    NULL                                        /* XXX - fill me in */
1690
  },
1691
  {
1692
    "Output Formfeed Disposition",              /* RFC 655 */
1693
    &ett_ffdisp_subopt,
1694
    FIXED_LENGTH,
1695
    2,
1696
    NULL                                        /* XXX - fill me in */
1697
  },
1698
  {
1699
    "Output Vertical Tabstops",                 /* RFC 656 */
1700
    &ett_vtstops_subopt,
1701
    VARIABLE_LENGTH,
1702
    1,
1703
    NULL                                        /* XXX - fill me in */
1704
  },
1705
  {
1706
    "Output Vertical Tab Disposition",          /* RFC 657 */
1707
    &ett_vtdisp_subopt,
1708
    FIXED_LENGTH,
1709
    2,
1710
    NULL                                        /* XXX - fill me in */
1711
  },
1712
  {
1713
    "Output Linefeed Disposition",              /* RFC 658 */
1714
    &ett_lfdisp_subopt,
1715
    FIXED_LENGTH,
1716
    2,
1717
    NULL                                        /* XXX - fill me in */
1718
  },
1719
  {
1720
    "Extended ASCII",                           /* RFC 698 */
1721
    &ett_extasc_subopt,
1722
    FIXED_LENGTH,
1723
    2,
1724
    NULL                                        /* XXX - fill me in */
1725
  },
1726
  {
1727
    "Logout",                                   /* RFC 727 */
1728
    NULL,                                       /* no suboption negotiation */
1729
    NO_LENGTH,
1730
    0,
1731
    NULL
1732
  },
1733
  {
1734
    "Byte Macro",                               /* RFC 735 */
1735
    &ett_bytemacro_subopt,
1736
    VARIABLE_LENGTH,
1737
    2,
1738
    NULL                                        /* XXX - fill me in */
1739
  },
1740
  {
1741
    "Data Entry Terminal",                      /* RFC 732, RFC 1043 */
1742
    &ett_det_subopt,
1743
    VARIABLE_LENGTH,
1744
    2,
1745
    NULL                                        /* XXX - fill me in */
1746
  },
1747
  {
1748
    "SUPDUP",                                   /* RFC 734, RFC 736 */
1749
    NULL,                                       /* no suboption negotiation */
1750
    NO_LENGTH,
1751
    0,
1752
    NULL
1753
  },
1754
  {
1755
    "SUPDUP Output",                            /* RFC 749 */
1756
    &ett_supdupout_subopt,
1757
    VARIABLE_LENGTH,
1758
    1,
1759
    NULL                                        /* XXX - fill me in */
1760
  },
1761
  {
1762
    "Send Location",                            /* RFC 779 */
1763
    &ett_sendloc_subopt,
1764
    VARIABLE_LENGTH,
1765
    0,
1766
    NULL                                        /* XXX - fill me in */
1767
  },
1768
  {
1769
    "Terminal Type",                            /* RFC 1091 */
1770
    &ett_termtype_subopt,
1771
    VARIABLE_LENGTH,
1772
    1,
1773
    dissect_string_subopt
1774
  },
1775
  {
1776
    "End of Record",                            /* RFC 885 */
1777
    NULL,                                       /* no suboption negotiation */
1778
    NO_LENGTH,
1779
    0,
1780
    NULL
1781
  },
1782
  {
1783
    "TACACS User Identification",               /* RFC 927 */
1784
    &ett_tacacsui_subopt,
1785
    FIXED_LENGTH,
1786
    4,
1787
    NULL                                        /* XXX - fill me in */
1788
  },
1789
  {
1790
    "Output Marking",                           /* RFC 933 */
1791
    &ett_outmark_subopt,
1792
    VARIABLE_LENGTH,
1793
    1,
1794
    dissect_outmark_subopt,
1795
  },
1796
  {
1797
    "Terminal Location Number",                 /* RFC 946 */
1798
    &ett_tlocnum_subopt,
1799
    VARIABLE_LENGTH,
1800
    1,
1801
    NULL                                        /* XXX - fill me in */
1802
  },
1803
  {
1804
    "Telnet 3270 Regime",                       /* RFC 1041 */
1805
    &ett_tn3270reg_subopt,
1806
    VARIABLE_LENGTH,
1807
    1,
1808
    dissect_tn3270_regime_subopt
1809
  },
1810
  {
1811
    "X.3 PAD",                                  /* RFC 1053 */
1812
    &ett_x3pad_subopt,
1813
    VARIABLE_LENGTH,
1814
    1,
1815
    NULL                                        /* XXX - fill me in */
1816
  },
1817
  {
1818
    "Negotiate About Window Size",              /* RFC 1073, DW183 */
1819
    &ett_naws_subopt,
1820
    FIXED_LENGTH,
1821
    4,
1822
    dissect_naws_subopt
1823
  },
1824
  {
1825
    "Terminal Speed",                           /* RFC 1079 */
1826
    &ett_tspeed_subopt,
1827
    VARIABLE_LENGTH,
1828
    1,
1829
    NULL                                        /* XXX - fill me in */
1830
  },
1831
  {
1832
    "Remote Flow Control",                      /* RFC 1372 */
1833
    &ett_rfc_subopt,
1834
    FIXED_LENGTH,
1835
    1,
1836
    dissect_rfc_subopt
1837
  },
1838
  {
1839
    "Linemode",                                 /* RFC 1184 */
1840
    &ett_linemode_subopt,
1841
    VARIABLE_LENGTH,
1842
    1,
1843
    NULL                                        /* XXX - fill me in */
1844
  },
1845
  {
1846
    "X Display Location",                       /* RFC 1096 */
1847
    &ett_xdpyloc_subopt,
1848
    VARIABLE_LENGTH,
1849
    1,
1850
    dissect_string_subopt
1851
  },
1852
  {
1853
    "Environment Option",                       /* RFC 1408, RFC 1571 */
1854
    &ett_env_subopt,
1855
    VARIABLE_LENGTH,
1856
    1,
1857
    NULL                                        /* XXX - fill me in */
1858
  },
1859
  {
1860
    "Authentication Option",                    /* RFC 2941 */
1861
    &ett_auth_subopt,
1862
    VARIABLE_LENGTH,
1863
    1,
1864
    dissect_authentication_subopt
1865
  },
1866
  {
1867
    "Encryption Option",                        /* RFC 2946 */
1868
    &ett_enc_subopt,
1869
    VARIABLE_LENGTH,
1870
    1,
1871
    dissect_encryption_subopt
1872
  },
1873
  {
1874
    "New Environment Option",                   /* RFC 1572 */
1875
    &ett_newenv_subopt,
1876
    VARIABLE_LENGTH,
1877
    1,
1878
    NULL                                        /* XXX - fill me in */
1879
  },
1880
  {
1881
    "TN3270E",                                  /* RFC 1647 */
1882
    &ett_tn3270e_subopt,
1883
    VARIABLE_LENGTH,
1884
    1,
1885
    dissect_tn3270e_subopt
1886
  },
1887
  {
1888
    "XAUTH",                                    /* XAUTH  */
1889
    &ett_xauth_subopt,
1890
    VARIABLE_LENGTH,
1891
    1,
1892
    NULL                                        /* XXX - fill me in */
1893
  },
1894
  {
1895
    "CHARSET",                                  /* CHARSET  */
1896
    &ett_charset_subopt,
1897
    VARIABLE_LENGTH,
1898
    1,
1899
    NULL                                        /* XXX - fill me in */
1900
  },
1901
  {
1902
    "Remote Serial Port",                       /* Remote Serial Port */
1903
    &ett_rsp_subopt,
1904
    VARIABLE_LENGTH,
1905
    1,
1906
    NULL                                        /* XXX - fill me in */
1907
  },
1908
  {
1909
    "COM Port Control",                         /* RFC 2217 */
1910
    &ett_comport_subopt,
1911
    VARIABLE_LENGTH,
1912
    1,
1913
    dissect_comport_subopt
1914
  },
1915
  {
1916
    "Suppress Local Echo",                      /* draft-rfced-exp-atmar-00 */
1917
    NULL,
1918
    NO_LENGTH,
1919
    0,
1920
    NULL
1921
  },
1922
  {
1923
    "Start TLS",                                /* draft-ietf-tn3270e-telnet-tls-06 */
1924
    &ett_starttls_subopt,
1925
    FIXED_LENGTH,
1926
    1,
1927
    dissect_starttls_subopt
1928
  },
1929
  {
1930
    "KERMIT",                                   /* RFC 2840 */
1931
    NULL,
1932
    VARIABLE_LENGTH,
1933
    1,
1934
    NULL                                        /* XXX - stub */
1935
  },
1936
  {
1937
    "SEND-URL",                                 /* draft-croft-telnet-url-trans-00 */
1938
    NULL,
1939
    VARIABLE_LENGTH,
1940
    1,
1941
    NULL                                        /* XXX - stub */
1942
  },
1943
  {
1944
    "FORWARD_X",                                /* draft-altman-telnet-fwdx-03 */
1945
    NULL,
1946
    VARIABLE_LENGTH,
1947
    1,
1948
    NULL                                        /* XXX - stub */
1949
  }
1950
1951
};
1952
1953
static const tn_opt telnet_opt_vmware = {
1954
  "VMware Virtual Serial Port Proxy",
1955
  NULL,
1956
  VARIABLE_LENGTH,
1957
  1,
1958
  dissect_vmware_subopt
1959
};
1960
1961
static const tn_opt telnet_opt_unknown = {
1962
  "<unknown option>",
1963
  NULL,
1964
  VARIABLE_LENGTH,
1965
  0,
1966
  NULL
1967
};
1968
1969
static const tn_opt *
1970
telnet_find_option(uint8_t opt_byte)
1971
5.80k
{
1972
5.80k
  if (opt_byte < array_length(options))
1973
4.31k
    return &options[opt_byte];
1974
1975
1.48k
  if (opt_byte == VMWARE_TELNET_EXT)
1976
292
    return &telnet_opt_vmware;
1977
1978
1.19k
  return &telnet_opt_unknown;
1979
1.48k
}
1980
1981
static int
1982
telnet_sub_option(packet_info *pinfo, proto_tree *option_tree, proto_item *option_item, tvbuff_t *tvb, int start_offset)
1983
2.49k
{
1984
2.49k
  int           offset = start_offset;
1985
2.49k
  uint8_t       opt_byte;
1986
2.49k
  const tn_opt *opt;
1987
2.49k
  int           subneg_len;
1988
2.49k
  int           iac_offset;
1989
2.49k
  unsigned      len;
1990
2.49k
  tvbuff_t     *unescaped_tvb;
1991
2.49k
  int           cur_offset;
1992
2.49k
  bool          iac_found;
1993
1994
  /*
1995
   * As data with value iac (0xff) is possible, this value must be escaped
1996
   * with iac (rfc 854).
1997
   */
1998
2.49k
  int  iac_data = 0;
1999
2000
2.49k
  offset += 2;  /* skip IAC and SB */
2001
2002
  /* Get the option code */
2003
2.49k
  opt_byte = tvb_get_uint8(tvb, offset);
2004
2.49k
  opt = telnet_find_option(opt_byte);
2005
2.49k
  offset++;
2006
2007
  /* Search for an unescaped IAC. */
2008
2.49k
  cur_offset = offset;
2009
2.49k
  len = tvb_reported_length_remaining(tvb, offset);
2010
4.50k
  do {
2011
4.50k
    iac_offset = tvb_find_uint8(tvb, cur_offset, len, TN_IAC);
2012
4.50k
    iac_found = true;
2013
4.50k
    if (iac_offset == -1) {
2014
      /* None found - run to the end of the packet. */
2015
111
      offset += len;
2016
4.39k
    } else {
2017
4.39k
      if (!tvb_offset_exists(tvb, iac_offset + 1) ||
2018
4.38k
          (tvb_get_uint8(tvb, iac_offset + 1) != TN_IAC)) {
2019
        /* We really found a single IAC, so we're done */
2020
2.38k
        offset = iac_offset;
2021
2.38k
      } else {
2022
        /*
2023
         * We saw an escaped IAC, so we have to move ahead to the
2024
         * next section
2025
         */
2026
2.01k
        iac_found = false;
2027
2.01k
        cur_offset = iac_offset + 2;
2028
2.01k
        iac_data += 1;
2029
2.01k
      }
2030
4.39k
    }
2031
2032
4.50k
  } while (!iac_found);
2033
2034
2.49k
  subneg_len = offset - start_offset;
2035
2036
2.49k
  start_offset += 3;    /* skip IAC, SB, and option code */
2037
2.49k
  subneg_len -= 3;
2038
2039
2.49k
  if (subneg_len > 0) {
2040
2041
    /* Now dissect the suboption parameters. */
2042
2.23k
    if (opt->dissect != NULL) {
2043
2044
1.85k
      switch (opt->len_type) {
2045
2046
0
      case NO_LENGTH:
2047
        /* There isn't supposed to *be* sub-option negotiation for this. */
2048
0
        expert_add_info_format(pinfo, option_item, &ei_telnet_suboption_length, "Bogus suboption data");
2049
0
        return offset;
2050
2051
242
      case FIXED_LENGTH:
2052
        /* Make sure the length is what it's supposed to be. */
2053
242
        if (subneg_len - iac_data != opt->optlen) {
2054
191
          expert_add_info_format(pinfo, option_item, &ei_telnet_suboption_length, "Suboption parameter length is %d, should be %d", subneg_len, opt->optlen);
2055
191
          return offset;
2056
191
        }
2057
51
        break;
2058
2059
1.60k
      case VARIABLE_LENGTH:
2060
        /* Make sure the length is greater than the minimum. */
2061
1.60k
        if (subneg_len - iac_data < opt->optlen) {
2062
0
          expert_add_info_format(pinfo, option_item, &ei_telnet_suboption_length, "Suboption parameter length is %d, should be at least %d", subneg_len, opt->optlen);
2063
0
          return offset;
2064
0
        }
2065
1.60k
        break;
2066
1.85k
      }
2067
2068
      /* We have a dissector for this suboption's parameters; call it. */
2069
1.65k
      if (iac_data > 0) {
2070
        /* Data is escaped, we have to unescape it. */
2071
422
        unescaped_tvb = unescape_and_tvbuffify_telnet_option(pinfo, tvb, start_offset, subneg_len);
2072
422
        (*opt->dissect)(pinfo, opt->name, unescaped_tvb, 0, subneg_len - iac_data, option_tree, option_item);
2073
1.23k
      } else {
2074
1.23k
        (*opt->dissect)(pinfo, opt->name, tvb, start_offset, subneg_len, option_tree, option_item);
2075
1.23k
      }
2076
1.65k
    } else {
2077
      /* We don't have a dissector for them; just show them as data. */
2078
380
      if (iac_data > 0) {
2079
        /* Data is escaped, we have to unescape it. */
2080
127
        unescaped_tvb = unescape_and_tvbuffify_telnet_option(pinfo, tvb, start_offset, subneg_len);
2081
127
        proto_tree_add_item(option_tree, hf_telnet_option_data, unescaped_tvb, 0, subneg_len - iac_data, ENC_NA);
2082
253
      } else {
2083
253
        proto_tree_add_item(option_tree, hf_telnet_option_data, tvb, start_offset, subneg_len, ENC_NA);
2084
253
      }
2085
380
    }
2086
2.23k
  }
2087
2.30k
  return offset;
2088
2.49k
}
2089
2090
static void
2091
telnet_suboption_name(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int* offset, const char** optname,
2092
                      proto_tree **opt_tree, proto_item **opt_item, const char *type)
2093
3.31k
{
2094
3.31k
  uint8_t       opt_byte;
2095
3.31k
  const tn_opt *opt;
2096
3.31k
  int           ett = ett_telnet_subopt;
2097
2098
3.31k
  opt_byte = tvb_get_uint8(tvb, *offset);
2099
3.31k
  opt = telnet_find_option(opt_byte);
2100
3.31k
  if (opt->subtree_index != NULL)
2101
2.00k
    ett = *(opt->subtree_index);
2102
3.31k
  *opt_item = proto_tree_add_uint_format_value(tree, hf_telnet_subcmd, tvb, *offset, 1, opt_byte, "%s", opt->name);
2103
3.31k
  *opt_tree = proto_item_add_subtree(*opt_item, ett);
2104
2105
3.31k
  (*offset)++;
2106
3.31k
  (*optname) = wmem_strdup_printf(pinfo->pool, "%s %s", type, opt->name);
2107
3.31k
}
2108
2109
static int
2110
telnet_command(packet_info *pinfo, proto_tree *telnet_tree, tvbuff_t *tvb, int start_offset, unsigned *num_info_items)
2111
8.89k
{
2112
8.89k
  int    offset = start_offset;
2113
8.89k
  unsigned char optcode;
2114
8.89k
  const char* optname;
2115
8.89k
  proto_item *cmd_item, *subopt_item = NULL;
2116
8.89k
  proto_tree *cmd_tree, *subopt_tree = NULL;
2117
2118
8.89k
  offset += 1;  /* skip IAC */
2119
8.89k
  optcode = tvb_get_uint8(tvb, offset);
2120
2121
8.89k
  cmd_tree = proto_tree_add_subtree(telnet_tree, tvb, start_offset, 2, ett_telnet_cmd, &cmd_item, "Command header");
2122
8.89k
  proto_tree_add_item(cmd_tree, hf_telnet_cmd, tvb, offset, 1, ENC_BIG_ENDIAN);
2123
8.89k
  offset++;
2124
2125
8.89k
  switch(optcode) {
2126
121
  case TN_WILL:
2127
121
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Will");
2128
121
    break;
2129
2130
121
  case TN_WONT:
2131
121
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Won't");
2132
121
    break;
2133
2134
273
  case TN_DO:
2135
273
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Do");
2136
273
    break;
2137
2138
305
  case TN_DONT:
2139
305
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Don't");
2140
305
    break;
2141
2142
2.49k
  case TN_SB:
2143
2.49k
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Suboption");
2144
2.49k
    break;
2145
2146
5.58k
  default:
2147
5.58k
    optname = val_to_str_const(optcode, cmd_vals, "<unknown option>");
2148
5.58k
    break;
2149
8.89k
  }
2150
2151
8.89k
  proto_item_set_text(cmd_item, "%s", optname);
2152
8.89k
  if (optcode != TN_SE) {
2153
8.84k
    add_telnet_info_str(pinfo, num_info_items, optname);
2154
8.84k
  }
2155
2156
8.89k
  if (optcode == TN_SB) {
2157
2.49k
    offset = telnet_sub_option(pinfo, subopt_tree, subopt_item, tvb, start_offset);
2158
2.49k
  }
2159
2160
8.89k
  proto_item_set_len(cmd_item, offset-start_offset);
2161
2162
8.89k
  return offset;
2163
8.89k
}
2164
2165
static void
2166
telnet_add_text(proto_tree *tree, tvbuff_t *tvb, int offset, int len)
2167
4.36k
{
2168
4.36k
  int      next_offset;
2169
4.36k
  int      linelen;
2170
4.36k
  uint8_t  c;
2171
4.36k
  bool last_char_was_cr;
2172
2173
9.79k
  while (len != 0 && tvb_offset_exists(tvb, offset)) {
2174
    /*
2175
     * Find the end of the line.
2176
     */
2177
5.43k
    linelen = tvb_find_line_end(tvb, offset, len, &next_offset, false);
2178
5.43k
    len -= next_offset - offset;        /* subtract out the line's characters */
2179
2180
    /*
2181
     * In Telnet, CR NUL is the way you send a CR by itself in the
2182
     * default ASCII mode; don't treat CR by itself as a line ending,
2183
     * treat only CR NUL, CR LF, or LF by itself as a line ending.
2184
     */
2185
5.43k
    if (next_offset == offset + linelen + 1 && len >= 1) {
2186
      /*
2187
       * Well, we saw a one-character line ending, so either it's a CR
2188
       * or an LF; we have at least two characters left, including the
2189
       * CR.
2190
       *
2191
       * If the line ending is a CR, skip all subsequent CRs; at
2192
       * least one capture appeared to have multiple CRs at the end of
2193
       * a line.
2194
       */
2195
1.18k
      if (tvb_get_uint8(tvb, offset + linelen) == '\r') {
2196
296
        last_char_was_cr = true;
2197
6.70k
        while (len != 0 && tvb_offset_exists(tvb, next_offset)) {
2198
6.53k
          c = tvb_get_uint8(tvb, next_offset);
2199
6.53k
          next_offset++;        /* skip over that character */
2200
6.53k
          len--;
2201
6.53k
          if (c == '\n' || (c == '\0' && last_char_was_cr)) {
2202
            /*
2203
             * LF is a line ending, whether preceded by CR or not.
2204
             * NUL is a line ending if preceded by CR.
2205
             */
2206
130
            break;
2207
130
          }
2208
6.40k
          last_char_was_cr = (c == '\r');
2209
6.40k
        }
2210
296
      }
2211
1.18k
    }
2212
2213
    /*
2214
     * Now compute the length of the line *including* the end-of-line
2215
     * indication, if any; we display it all.
2216
     */
2217
5.43k
    linelen = next_offset - offset;
2218
2219
5.43k
    proto_tree_add_item(tree, hf_telnet_data, tvb, offset, linelen, ENC_ASCII);
2220
5.43k
    offset = next_offset;
2221
5.43k
  }
2222
4.36k
}
2223
2224
static int find_unescaped_iac(tvbuff_t *tvb, int offset, int len)
2225
9.32k
{
2226
9.32k
  int iac_offset = offset;
2227
2228
  /* If we find an IAC (0XFF), make sure it is not followed by another 0XFF.
2229
     Such cases indicate that it is not an IAC at all */
2230
15.5k
  while ((iac_offset = tvb_find_uint8(tvb, iac_offset, len, TN_IAC)) != -1 &&
2231
15.1k
         (tvb_get_uint8(tvb, iac_offset + 1) == TN_IAC))
2232
6.21k
  {
2233
6.21k
    iac_offset+=2;
2234
6.21k
    len = tvb_reported_length_remaining(tvb, iac_offset);
2235
6.21k
  }
2236
9.32k
  return iac_offset;
2237
9.32k
}
2238
2239
static int
2240
dissect_telnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2241
558
{
2242
558
  proto_tree *telnet_tree, *ti;
2243
558
  tvbuff_t   *next_tvb;
2244
558
  int         offset    = 0;
2245
558
  unsigned    len       = 0;
2246
558
  unsigned    is_tn3270 = 0;
2247
558
  unsigned    is_tn5250 = 0;
2248
558
  int         data_len;
2249
558
  int         iac_offset;
2250
558
  unsigned    num_info_items = 0;
2251
2252
558
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "TELNET");
2253
558
  col_set_str(pinfo->cinfo, COL_INFO, "Telnet Data" UTF8_HORIZONTAL_ELLIPSIS);
2254
2255
558
  is_tn3270 = find_tn3270_conversation(pinfo);
2256
558
  is_tn5250 = find_tn5250_conversation(pinfo);
2257
2258
558
  ti = proto_tree_add_item(tree, proto_telnet, tvb, offset, -1, ENC_NA);
2259
558
  telnet_tree = proto_item_add_subtree(ti, ett_telnet);
2260
2261
  /*
2262
   * Scan through the buffer looking for an IAC byte.
2263
   */
2264
9.46k
  while ((len = tvb_reported_length_remaining(tvb, offset)) > 0) {
2265
9.32k
    iac_offset = find_unescaped_iac(tvb, offset, len);
2266
9.32k
    if (iac_offset != -1) {
2267
      /*
2268
       * We found an IAC byte.
2269
       * If there's any data before it, add that data to the
2270
       * tree, a line at a time.
2271
       */
2272
8.91k
      data_len = iac_offset - offset;
2273
8.91k
      if (data_len > 0) {
2274
5.74k
        add_telnet_data_bytes_str(pinfo, &num_info_items, data_len);
2275
5.74k
        if (is_tn3270) {
2276
1.66k
          next_tvb = tvb_new_subset_length(tvb, offset, data_len);
2277
1.66k
          call_dissector(tn3270_handle, next_tvb, pinfo, telnet_tree);
2278
4.08k
        } else if (is_tn5250) {
2279
0
          next_tvb = tvb_new_subset_length(tvb, offset, data_len);
2280
0
          call_dissector(tn5250_handle, next_tvb, pinfo, telnet_tree);
2281
0
        } else
2282
4.08k
          telnet_add_text(telnet_tree, tvb, offset, data_len);
2283
5.74k
      }
2284
      /*
2285
       * Now interpret the command.
2286
       */
2287
8.91k
      offset = telnet_command(pinfo, telnet_tree, tvb, iac_offset, &num_info_items);
2288
8.91k
    } else {
2289
      /* get more data if tn3270 */
2290
413
      if (is_tn3270 || is_tn5250) {
2291
109
        pinfo->desegment_offset = offset;
2292
109
        pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
2293
109
        return tvb_captured_length(tvb);
2294
109
      }
2295
      /*
2296
       * We found no IAC byte, so what remains in the buffer
2297
       * is the last of the data in the packet.
2298
       * Add it to the tree, a line at a time, and then quit.
2299
       */
2300
304
      if (len > 0) {
2301
272
        add_telnet_data_bytes_str(pinfo, &num_info_items, len);
2302
272
        telnet_add_text(telnet_tree, tvb, offset, len);
2303
272
      }
2304
304
      break;
2305
413
    }
2306
9.32k
  }
2307
449
  return tvb_captured_length(tvb);
2308
558
}
2309
2310
void
2311
proto_register_telnet(void)
2312
14
{
2313
14
  static hf_register_info hf[] = {
2314
14
    { &hf_telnet_cmd,
2315
14
      { "Command", "telnet.cmd", FT_UINT8, BASE_DEC,
2316
14
        VALS(cmd_vals), 0, NULL, HFILL }
2317
14
    },
2318
14
    { &hf_telnet_subcmd,
2319
14
      { "Subcommand", "telnet.subcmd", FT_UINT8, BASE_DEC,
2320
14
        NULL, 0, NULL, HFILL }
2321
14
    },
2322
14
    { &hf_telnet_auth_name,
2323
14
      { "Name", "telnet.auth.name", FT_STRING, BASE_NONE,
2324
14
        NULL, 0, "Name of user being authenticated", HFILL }
2325
14
    },
2326
14
    { &hf_telnet_auth_cmd,
2327
14
      { "Auth Cmd", "telnet.auth.cmd", FT_UINT8, BASE_DEC,
2328
14
        VALS(auth_cmd_vals), 0, "Authentication Command", HFILL }
2329
14
    },
2330
14
    { &hf_telnet_auth_type,
2331
14
      { "Auth Type", "telnet.auth.type", FT_UINT8, BASE_DEC,
2332
14
        VALS(auth_type_vals), 0, "Authentication Type", HFILL }
2333
14
    },
2334
14
    { &hf_telnet_auth_mod_cred_fwd,
2335
14
      { "Cred Fwd", "telnet.auth.mod.cred_fwd", FT_BOOLEAN, 8,
2336
14
        TFS(&auth_mod_cred_fwd), 0x08, "Modifier: Whether client will forward creds or not", HFILL }
2337
14
    },
2338
14
    { &hf_telnet_auth_mod_who,
2339
14
      { "Who", "telnet.auth.mod.who", FT_BOOLEAN, 8,
2340
14
        TFS(&tfs_s2c_c2s), 0x01, "Modifier: Who will authenticate", HFILL }
2341
14
    },
2342
14
    { &hf_telnet_auth_mod_how,
2343
14
      { "How", "telnet.auth.mod.how", FT_BOOLEAN, 8,
2344
14
        TFS(&auth_mod_how), 0x02, "Modifier: Authentication flow", HFILL }
2345
14
    },
2346
14
    { &hf_telnet_auth_mod_enc,
2347
14
      { "Encrypt", "telnet.auth.mod.enc", FT_UINT8, BASE_DEC,
2348
14
        VALS(auth_mod_enc), 0x14, "Modifier: How to enable Encryption", HFILL }
2349
14
    },
2350
14
    { &hf_telnet_auth_krb5_type,
2351
14
      { "Command", "telnet.auth.krb5.cmd", FT_UINT8, BASE_DEC,
2352
14
        VALS(auth_krb5_types), 0, "Krb5 Authentication sub-command", HFILL }
2353
14
    },
2354
14
    { &hf_telnet_auth_ssl_status,
2355
14
      { "Status", "telnet.auth.ssl.status", FT_UINT8, BASE_DEC,
2356
14
        VALS(ssl_auth_status), 0, "SSL authentication status", HFILL }
2357
14
    },
2358
14
    { &hf_telnet_auth_data,
2359
14
      { "Authentication data", "telnet.auth.data", FT_BYTES, BASE_NONE,
2360
14
        NULL, 0, NULL, HFILL }
2361
14
    },
2362
14
    { &hf_telnet_string_subopt_value,
2363
14
      { "Value", "telnet.string_subopt.value", FT_STRING, BASE_NONE,
2364
14
        NULL, 0, NULL, HFILL }
2365
14
    },
2366
14
    { &hf_telnet_naws_subopt_width,
2367
14
      { "Width", "telnet.naws_subopt.width", FT_UINT16, BASE_DEC,
2368
14
        NULL, 0, NULL, HFILL }
2369
14
    },
2370
14
    { &hf_telnet_naws_subopt_height,
2371
14
      { "Height", "telnet.naws_subopt.height", FT_UINT16, BASE_DEC,
2372
14
        NULL, 0, NULL, HFILL }
2373
14
    },
2374
14
    { &hf_telnet_outmark_subopt_cmd,
2375
14
      { "Command", "telnet.outmark_subopt.cmd", FT_CHAR, BASE_HEX,
2376
14
        VALS(telnet_outmark_subopt_cmd_vals), 0, NULL, HFILL }
2377
14
    },
2378
14
    { &hf_telnet_outmark_subopt_banner,
2379
14
      { "Banner", "telnet.outmark_subopt.banner", FT_STRING, BASE_NONE,
2380
14
        NULL, 0, NULL, HFILL }
2381
14
    },
2382
14
    { &hf_telnet_comport_subopt_signature,
2383
14
      { "Signature", "telnet.comport_subopt.signature", FT_STRING, BASE_NONE,
2384
14
        NULL, 0, NULL, HFILL }
2385
14
    },
2386
14
    { &hf_telnet_comport_subopt_baud_rate,
2387
14
      { "Baud Rate", "telnet.comport_subopt.baud_rate", FT_UINT32, BASE_DEC,
2388
14
        NULL, 0, NULL, HFILL }
2389
14
    },
2390
14
    { &hf_telnet_comport_subopt_data_size,
2391
14
      { "Data Size", "telnet.comport_subopt.data_size", FT_UINT8, BASE_DEC,
2392
14
        NULL, 0, NULL, HFILL }
2393
14
    },
2394
14
    { &hf_telnet_comport_subopt_parity,
2395
14
      { "Parity", "telnet.comport_subopt.parity", FT_UINT16, BASE_DEC,
2396
14
        NULL, 0, NULL, HFILL }
2397
14
    },
2398
14
    { &hf_telnet_comport_subopt_stop,
2399
14
      { "Stop Bits", "telnet.comport_subopt.stop", FT_UINT16, BASE_DEC,
2400
14
        NULL, 0, NULL, HFILL }
2401
14
    },
2402
14
    { &hf_telnet_comport_subopt_control,
2403
14
      { "Control", "telnet.comport_subopt.control", FT_UINT16, BASE_DEC,
2404
14
        NULL, 0, NULL, HFILL }
2405
14
    },
2406
14
    { &hf_telnet_comport_linestate,
2407
14
      { "Linestate", "telnet.comport_subopt.linestate", FT_STRING, BASE_NONE,
2408
14
        NULL, 0, NULL, HFILL }
2409
14
    },
2410
14
    { &hf_telnet_comport_set_linestate_mask,
2411
14
      { "Set Linestate Mask", "telnet.comport_subopt.set_linestate_mask", FT_STRING, BASE_NONE,
2412
14
        NULL, 0, NULL, HFILL }
2413
14
    },
2414
14
    { &hf_telnet_comport_modemstate,
2415
14
      { "Modemstate", "telnet.comport_subopt.modemstate", FT_STRING, BASE_NONE,
2416
14
        NULL, 0, NULL, HFILL }
2417
14
    },
2418
14
    { &hf_telnet_comport_set_modemstate_mask,
2419
14
      { "Set Modemstate Mask", "telnet.comport_subopt.set_modemstate_mask", FT_STRING, BASE_NONE,
2420
14
        NULL, 0, NULL, HFILL }
2421
14
    },
2422
14
    { &hf_telnet_comport_subopt_flow_control_suspend,
2423
14
      { "Flow Control Suspend", "telnet.comport_subopt.flow_control_suspend", FT_NONE, BASE_NONE,
2424
14
        NULL, 0, NULL, HFILL }
2425
14
    },
2426
14
    { &hf_telnet_comport_subopt_flow_control_resume,
2427
14
      { "Flow Control Resume", "telnet.comport_subopt.flow_control_resume", FT_NONE, BASE_NONE,
2428
14
        NULL, 0, NULL, HFILL }
2429
14
    },
2430
14
    { &hf_telnet_comport_subopt_purge,
2431
14
      { "Purge", "telnet.comport_subopt.purge", FT_UINT16, BASE_DEC,
2432
14
        NULL, 0, NULL, HFILL }
2433
14
    },
2434
14
    { &hf_telnet_rfc_subopt_cmd,
2435
14
      { "Command", "telnet.rfc_subopt.cmd", FT_UINT8, BASE_DEC,
2436
14
        VALS(rfc_opt_vals), 0, NULL, HFILL }
2437
14
    },
2438
14
    { &hf_telnet_tabstop,
2439
14
      { "Tabstop value", "telnet.tabstop", FT_UINT8, BASE_DEC,
2440
14
        NULL, 0, NULL, HFILL }
2441
14
    },
2442
14
    { &hf_telnet_enc_cmd,
2443
14
      { "Enc Cmd", "telnet.enc.cmd", FT_UINT8, BASE_DEC,
2444
14
        VALS(enc_cmd_vals), 0, "Encryption command", HFILL }
2445
14
    },
2446
14
    { &hf_telnet_enc_type,
2447
14
      { "Enc Type", "telnet.enc.type", FT_UINT8, BASE_DEC,
2448
14
        VALS(enc_type_vals), 0, "Encryption type", HFILL }
2449
14
    },
2450
14
    { &hf_telnet_enc_type_data,
2451
14
      { "Type-specific data", "telnet.enc.type_data", FT_BYTES, BASE_NONE,
2452
14
        NULL, 0, NULL, HFILL }
2453
14
    },
2454
14
    { &hf_telnet_enc_key_id,
2455
14
      { "Key ID", "telnet.enc.key_id", FT_BYTES, BASE_NONE,
2456
14
        NULL, 0, NULL, HFILL }
2457
14
    },
2458
14
    { &hf_telnet_data,
2459
14
      { "Data", "telnet.data", FT_STRING, BASE_NONE,
2460
14
        NULL, 0, NULL, HFILL }
2461
14
    },
2462
14
    { &hf_telnet_option_data,
2463
14
      { "Option data", "telnet.option_data", FT_BYTES, BASE_NONE,
2464
14
        NULL, 0, NULL, HFILL }
2465
14
    },
2466
14
    { &hf_telnet_subcommand_data,
2467
14
      { "Subcommand data", "telnet.subcommand_data", FT_BYTES, BASE_NONE,
2468
14
        NULL, 0, NULL, HFILL }
2469
14
    },
2470
14
    { &hf_tn3270_subopt,
2471
14
      { "Suboption", "telnet.tn3270.subopt", FT_UINT8, BASE_DEC,
2472
14
        VALS(tn3270_subopt_vals), 0, NULL, HFILL }
2473
14
    },
2474
14
    { &hf_tn3270_connect,
2475
14
      { "Connect", "telnet.tn3270.connect", FT_STRING, BASE_NONE,
2476
14
        NULL, 0, NULL, HFILL }
2477
14
    },
2478
14
    { &hf_tn3270_is,
2479
14
      { "Is", "telnet.tn3270.is", FT_STRING, BASE_NONE,
2480
14
        NULL, 0, NULL, HFILL }
2481
14
    },
2482
14
    { &hf_tn3270_request_string,
2483
14
      { "Request", "telnet.tn3270.request_string", FT_STRING, BASE_NONE,
2484
14
        NULL, 0, NULL, HFILL }
2485
14
    },
2486
14
    { &hf_tn3270_reason,
2487
14
      { "Reason", "telnet.tn3270.reason", FT_UINT8, BASE_DEC,
2488
14
        VALS(tn3270_reason_vals), 0, NULL, HFILL }
2489
14
    },
2490
14
    { &hf_tn3270_request,
2491
14
      { "Request", "telnet.tn3270.request", FT_UINT8, BASE_DEC,
2492
14
        VALS(tn3270_request_vals), 0, NULL, HFILL }
2493
14
    },
2494
14
    { &hf_tn3270_regime_subopt_value,
2495
14
      { "Value", "telnet.tn3270.regime_subopt.value", FT_STRING, BASE_NONE,
2496
14
        NULL, 0, NULL, HFILL }
2497
14
    },
2498
14
    { &hf_tn3270_regime_cmd,
2499
14
      { "Cmd", "telnet.regime_cmd", FT_UINT8, BASE_DEC,
2500
14
        NULL, 0, NULL, HFILL }
2501
14
    },
2502
14
    { &hf_telnet_starttls,
2503
14
      { "Follows", "telnet.starttls", FT_UINT8, BASE_DEC,
2504
14
        NULL, 0, NULL, HFILL }
2505
14
    },
2506
14
    { &hf_telnet_vmware_cmd,
2507
14
      { "VMware Serial Port Proxy Cmd", "telnet.vmware.cmd", FT_UINT8, BASE_DEC,
2508
14
        VALS(vmware_cmd_vals), 0, "VMware command", HFILL }
2509
14
    },
2510
14
    { &hf_telnet_vmware_known_suboption_code,
2511
14
      { "Suboption", "telnet.vmware.known_suboption_code", FT_UINT8, BASE_DEC,
2512
14
        VALS(vmware_cmd_vals), 0, NULL, HFILL }
2513
14
    },
2514
14
    { &hf_telnet_vmware_unknown_subopt_code,
2515
14
      { "Code", "telnet.vmware.unknown_suboption_code", FT_UINT8, BASE_DEC,
2516
14
        NULL, 0, NULL, HFILL }
2517
14
    },
2518
14
    { &hf_telnet_vmware_vmotion_sequence,
2519
14
      { "vMotion sequence", "telnet.vmware.vmotion.sequence", FT_BYTES, BASE_NONE,
2520
14
        NULL, 0, NULL, HFILL }
2521
14
    },
2522
14
    { &hf_telnet_vmware_vmotion_secret,
2523
14
      { "vMotion secret", "telnet.vmware.vmotion.secret", FT_BYTES, BASE_NONE,
2524
14
        NULL, 0, NULL, HFILL }
2525
14
    },
2526
14
    { &hf_telnet_vmware_proxy_direction,
2527
14
      { "Proxy Direction", "telnet.vmware.proxy.direction", FT_CHAR, BASE_HEX,
2528
14
        VALS(vmware_proxy_direction_vals), 0, NULL, HFILL }
2529
14
    },
2530
14
    { &hf_telnet_vmware_proxy_serviceUri,
2531
14
      { "Proxy Service URI", "telnet.vmware.proxy.serviceUri", FT_STRING, BASE_NONE,
2532
14
        NULL, 0, NULL, HFILL }
2533
14
    },
2534
14
    { &hf_telnet_vmware_vm_vc_uuid,
2535
14
      { "VM VC UUID", "telnet.vmware.vm.vc_uuid", FT_STRING, BASE_NONE,
2536
14
        NULL, 0, NULL, HFILL }
2537
14
    },
2538
14
    { &hf_telnet_vmware_vm_bios_uuid,
2539
14
      { "VM BIOS UUID", "telnet.vmware.vm.bios_uuid", FT_STRING, BASE_NONE,
2540
14
        NULL, 0, NULL, HFILL }
2541
14
    },
2542
14
    { &hf_telnet_vmware_vm_location_uuid,
2543
14
      { "VM Location UUID", "telnet.vmware.vm.location_uuid", FT_STRING, BASE_NONE,
2544
14
        NULL, 0, NULL, HFILL }
2545
14
    },
2546
14
    { &hf_telnet_vmware_vm_name,
2547
14
      { "VM name", "telnet.vmware.vm.name", FT_STRING, BASE_NONE,
2548
14
        NULL, 0, NULL, HFILL }
2549
14
    },
2550
14
  };
2551
14
  static int *ett[] = {
2552
14
    &ett_telnet,
2553
14
    &ett_telnet_cmd,
2554
14
    &ett_telnet_subopt,
2555
14
    &ett_status_subopt,
2556
14
    &ett_rcte_subopt,
2557
14
    &ett_olw_subopt,
2558
14
    &ett_ops_subopt,
2559
14
    &ett_crdisp_subopt,
2560
14
    &ett_htstops_subopt,
2561
14
    &ett_htdisp_subopt,
2562
14
    &ett_ffdisp_subopt,
2563
14
    &ett_vtstops_subopt,
2564
14
    &ett_vtdisp_subopt,
2565
14
    &ett_lfdisp_subopt,
2566
14
    &ett_extasc_subopt,
2567
14
    &ett_bytemacro_subopt,
2568
14
    &ett_det_subopt,
2569
14
    &ett_supdupout_subopt,
2570
14
    &ett_sendloc_subopt,
2571
14
    &ett_termtype_subopt,
2572
14
    &ett_tacacsui_subopt,
2573
14
    &ett_outmark_subopt,
2574
14
    &ett_tlocnum_subopt,
2575
14
    &ett_tn3270reg_subopt,
2576
14
    &ett_x3pad_subopt,
2577
14
    &ett_naws_subopt,
2578
14
    &ett_tspeed_subopt,
2579
14
    &ett_rfc_subopt,
2580
14
    &ett_linemode_subopt,
2581
14
    &ett_xdpyloc_subopt,
2582
14
    &ett_env_subopt,
2583
14
    &ett_auth_subopt,
2584
14
    &ett_enc_subopt,
2585
14
    &ett_newenv_subopt,
2586
14
    &ett_tn3270e_subopt,
2587
14
    &ett_xauth_subopt,
2588
14
    &ett_charset_subopt,
2589
14
    &ett_rsp_subopt,
2590
14
    &ett_comport_subopt,
2591
14
    &ett_starttls_subopt,
2592
14
  };
2593
2594
14
  static ei_register_info ei[] = {
2595
14
      { &ei_telnet_invalid_subcommand, { "telnet.invalid_subcommand", PI_PROTOCOL, PI_WARN, "Invalid subcommand", EXPFILL }},
2596
14
      { &ei_telnet_invalid_baud_rate, { "telnet.invalid_baud_rate", PI_PROTOCOL, PI_WARN, "Invalid Baud Rate", EXPFILL }},
2597
14
      { &ei_telnet_invalid_data_size, { "telnet.invalid_data_size", PI_PROTOCOL, PI_WARN, "Invalid Data Size", EXPFILL }},
2598
14
      { &ei_telnet_invalid_parity, { "telnet.invalid_parity", PI_PROTOCOL, PI_WARN, "Invalid Parity Packet", EXPFILL }},
2599
14
      { &ei_telnet_invalid_stop, { "telnet.invalid_stop", PI_PROTOCOL, PI_WARN, "Invalid Stop Packet", EXPFILL }},
2600
14
      { &ei_telnet_invalid_control, { "telnet.invalid_control", PI_PROTOCOL, PI_WARN, "Invalid Control Packet", EXPFILL }},
2601
14
      { &ei_telnet_invalid_linestate, { "telnet.invalid_linestate", PI_PROTOCOL, PI_WARN, "Invalid linestate", EXPFILL }},
2602
14
      { &ei_telnet_invalid_modemstate, { "telnet.invalid_modemstate", PI_PROTOCOL, PI_WARN, "Invalid Modemstate", EXPFILL }},
2603
14
      { &ei_telnet_invalid_purge, { "telnet.invalid_purge", PI_PROTOCOL, PI_WARN, "Invalid Purge Packet", EXPFILL }},
2604
14
      { &ei_telnet_enc_cmd_unknown, { "telnet.enc.cmd.unknown", PI_PROTOCOL, PI_WARN, "Unknown encryption command", EXPFILL }},
2605
14
      { &ei_telnet_suboption_length, { "telnet.suboption_length.invalid", PI_PROTOCOL, PI_WARN, "Bogus suboption data", EXPFILL }},
2606
14
      { &ei_telnet_vmware_unexp_data, { "telnet.vmware.unexpected_data", PI_PROTOCOL, PI_WARN, "Unexpected VMware Serial Port Proxy negotiation data", EXPFILL }},
2607
14
  };
2608
2609
14
  expert_module_t* expert_telnet;
2610
2611
14
  proto_telnet = proto_register_protocol("Telnet", "TELNET", "telnet");
2612
14
  proto_register_field_array(proto_telnet, hf, array_length(hf));
2613
14
  proto_register_subtree_array(ett, array_length(ett));
2614
2615
14
  expert_telnet = expert_register_protocol(proto_telnet);
2616
14
  expert_register_field_array(expert_telnet, ei, array_length(ei));
2617
2618
14
  telnet_handle = register_dissector("telnet", dissect_telnet, proto_telnet);
2619
14
}
2620
2621
void
2622
proto_reg_handoff_telnet(void)
2623
14
{
2624
14
  dissector_add_uint_with_preference("tcp.port", TCP_PORT_TELNET, telnet_handle);
2625
2626
14
  dissector_add_uint("acdr.tls_application", TLS_APP_TELNET, telnet_handle);
2627
2628
14
  tn3270_handle = find_dissector_add_dependency("tn3270", proto_telnet);
2629
14
  tn5250_handle = find_dissector_add_dependency("tn5250", proto_telnet);
2630
14
  tls_handle = find_dissector("tls");
2631
14
}
2632
2633
/*
2634
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2635
 *
2636
 * Local Variables:
2637
 * c-basic-offset: 2
2638
 * tab-width: 8
2639
 * indent-tabs-mode: nil
2640
 * End:
2641
 *
2642
 * ex: set shiftwidth=2 tabstop=8 expandtab:
2643
 * :indentSize=2:tabSize=8:noTabs=true:
2644
 */