Coverage Report

Created: 2026-06-30 07:22

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
21.5k
#define TN_IAC   255
167
200
#define TN_DONT  254
168
96
#define TN_DO    253
169
94
#define TN_WONT  252
170
56
#define TN_WILL  251
171
5.90k
#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
4.65k
#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
  unsigned         optlen;        /* value length should be (minimum if VARIABLE) */
223
  void  (*dissect)(packet_info *pinfo, const char *, tvbuff_t *, unsigned, unsigned, 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
0
{
236
0
  int  model;
237
238
0
  if ((strcmp(terminaltype,"IBM-3278-2-E") == 0) || (strcmp(terminaltype,"IBM-3278-2") == 0) ||
239
0
      (strcmp(terminaltype,"IBM-3278-3") == 0) || (strcmp(terminaltype,"IBM-3278-4") == 0) ||
240
0
      (strcmp(terminaltype,"IBM-3278-5") == 0) || (strcmp(terminaltype,"IBM-3277-2") == 0) ||
241
0
      (strcmp(terminaltype,"IBM-3279-3") == 0) || (strcmp(terminaltype,"IBM-3279-4") == 0) ||
242
0
      (strcmp(terminaltype,"IBM-3279-2-E") == 0) || (strcmp(terminaltype,"IBM-3279-2") == 0) ||
243
0
      (strcmp(terminaltype,"IBM-3279-4-E") == 0)) {
244
0
    model = terminaltype[9] - '0';
245
0
    add_tn3270_conversation(pinfo, 0, model);
246
0
  }
247
0
}
248
249
static void
250
check_for_tn3270(packet_info *pinfo _U_, const char *optname, const char *terminaltype)
251
0
{
252
0
  if (strcmp(optname,"Terminal Type") != 0) {
253
0
    return;
254
0
  }
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
28
{
273
28
  conversation_t        *conversation = find_or_create_conversation(pinfo);
274
28
  telnet_conv_info_t    *telnet_info;
275
276
28
  telnet_info = (telnet_conv_info_t*)conversation_get_proto_data(conversation, proto_telnet);
277
28
  if (!telnet_info) {
278
9
    telnet_info = wmem_new0(wmem_file_scope(), telnet_conv_info_t);
279
9
    telnet_info->vmotion_sequence_len = -1;
280
9
    conversation_add_proto_data(conversation, proto_telnet, telnet_info);
281
9
  }
282
28
  return telnet_info;
283
28
}
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
7.95k
{
289
7.95k
  const unsigned max_info_items = 5; /* Arbitrary limit so the column doesn't end up too wide. */
290
291
7.95k
  if (*num_items == 0) {
292
    /* Replace the default info text. */
293
277
    col_add_str(pinfo->cinfo, COL_INFO, str);
294
7.67k
  } else if (*num_items < max_info_items) {
295
1.03k
    col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, str);
296
6.64k
  } else if (*num_items == max_info_items) {
297
    /* Too many to display.  Finish with an ellipsis. */
298
230
    col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, UTF8_HORIZONTAL_ELLIPSIS);
299
230
  }
300
7.95k
  (*num_items)++;
301
7.95k
}
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
3.33k
{
307
3.33k
  char str[30];
308
309
3.33k
  snprintf(str, sizeof str, "%u byte%s data", len, plurality(len, "", "s"));
310
3.33k
  add_telnet_info_str(pinfo, num_items, str);
311
3.33k
}
312
313
static void
314
dissect_string_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, unsigned offset, unsigned len,
315
                      proto_tree *tree, proto_item *item)
316
6
{
317
6
  uint8_t cmd;
318
319
6
  cmd = tvb_get_uint8(tvb, offset);
320
6
  switch (cmd) {
321
322
0
  case 0:       /* IS */
323
0
    proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Here's my %s", optname);
324
0
    offset++;
325
0
    len--;
326
0
    if (len > 0) {
327
0
      proto_tree_add_item(tree, hf_telnet_string_subopt_value, tvb, offset, len, ENC_ASCII);
328
0
    }
329
0
    check_for_tn3270(pinfo, optname, tvb_format_text(pinfo->pool, tvb, offset, len));
330
0
    break;
331
332
0
  case 1:       /* SEND */
333
0
    proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Send your %s", optname);
334
0
    offset++;
335
0
    len--;
336
0
    if (len > 0)
337
0
      proto_tree_add_bytes_format(tree, hf_telnet_subcommand_data, tvb, offset, len, NULL, "Extra data");
338
0
    break;
339
340
6
  default:
341
6
    expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
342
343
6
    offset++;
344
6
    len--;
345
6
    if (len > 0)
346
6
      proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
347
6
    break;
348
6
  }
349
6
}
350
351
static void
352
dissect_tn3270_regime_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, unsigned offset,
353
                       unsigned len, proto_tree *tree, proto_item *item _U_)
354
66
{
355
66
#define TN3270_REGIME_ARE          0x01
356
66
#define TN3270_REGIME_IS           0x00
357
358
66
  uint8_t cmd;
359
360
422
  while (len > 0) {
361
396
    cmd = tvb_get_uint8(tvb, offset);
362
396
    switch (cmd) {
363
14
    case TN3270_REGIME_ARE:
364
40
    case TN3270_REGIME_IS:
365
40
      if (cmd == TN3270_REGIME_ARE) {
366
14
        proto_tree_add_uint_format(tree, hf_tn3270_regime_cmd, tvb, offset, 1, cmd, "ARE");
367
14
        add_tn3270_conversation(pinfo, 0, 0);
368
26
      } else {
369
26
        proto_tree_add_uint_format(tree, hf_tn3270_regime_cmd, tvb, offset, 1, cmd, "IS");
370
26
      }
371
40
      proto_tree_add_item(tree, hf_tn3270_regime_subopt_value, tvb, offset + 1, len - 1, ENC_ASCII);
372
40
      return;
373
356
    default:
374
356
      proto_tree_add_uint_format(tree, hf_tn3270_regime_cmd, tvb, offset, 1, cmd, "Bogus value: %u", cmd);
375
356
      break;
376
396
    }
377
356
    offset++;
378
356
    len --;
379
356
  }
380
381
66
}
382
383
#define TN3270_ASSOCIATE          0x00
384
70
#define TN3270_CONNECT            0x01
385
350
#define TN3270_DEVICE_TYPE        0x02
386
194
#define TN3270_FUNCTIONS          0x03
387
156
#define TN3270_IS                 0x04
388
27
#define TN3270_REASON             0x05
389
#define TN3270_REJECT             0x06
390
194
#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, unsigned offset,
444
  unsigned len, proto_tree *tree, proto_item *item _U_)
445
157
{
446
447
157
  uint8_t cmd;
448
157
  unsigned    datalen;
449
157
  unsigned    connect_offset = 0;
450
157
  unsigned    device_type    = 0;
451
157
  unsigned    rsn            = 0;
452
453
3.82k
  while (len > 0) {
454
3.67k
    cmd = tvb_get_uint8(tvb, offset);
455
3.67k
    proto_tree_add_item( tree, hf_tn3270_subopt, tvb, offset, 1, ENC_BIG_ENDIAN );
456
3.67k
    switch (cmd) {
457
68
      case TN3270_CONNECT:
458
68
            proto_tree_add_item( tree, hf_tn3270_connect, tvb, offset + 1, len, ENC_ASCII );
459
68
            offset += (len - 1);
460
68
            len -= (len - 1);
461
68
            break;
462
156
      case TN3270_IS:
463
156
            device_type = tvb_get_uint8(tvb, offset-1);
464
156
            if (device_type == TN3270_DEVICE_TYPE) {
465
                /* If there is a terminal type to display, then it will be followed by CONNECT */
466
2
                if (tvb_find_uint8_length(tvb, offset + 1, len, TN3270_CONNECT, &connect_offset)) {
467
0
                  datalen = connect_offset - (offset + 1);
468
0
                  if (datalen > 0) {
469
0
                    proto_tree_add_item( tree, hf_tn3270_is, tvb, offset + 1, datalen, ENC_ASCII );
470
0
                    check_tn3270_model(pinfo, tvb_format_text(pinfo->pool, tvb, offset + 1, datalen));
471
0
                    offset += datalen;
472
0
                    len -= datalen;
473
0
                  }
474
0
                }
475
2
            }
476
156
            break;
477
27
      case TN3270_REASON:
478
27
            offset++;
479
27
            len--;
480
27
            proto_tree_add_item( tree, hf_tn3270_reason, tvb, offset, 1, ENC_BIG_ENDIAN );
481
27
            break;
482
194
      case TN3270_REQUEST:
483
194
            add_tn3270_conversation(pinfo, 1, 0);
484
194
            device_type = tvb_get_uint8(tvb, offset-1);
485
194
            if (device_type == TN3270_DEVICE_TYPE) {
486
0
              proto_tree_add_item( tree, hf_tn3270_request_string, tvb, offset + 1, len-1, ENC_ASCII );
487
0
              offset += (len - 1);
488
0
              len -= (len - 1);
489
194
            }else if (device_type == TN3270_FUNCTIONS) {
490
8
              while (len > 0) {
491
8
                rsn = tvb_get_uint8(tvb, offset);
492
8
                proto_tree_add_item( tree, hf_tn3270_request, tvb, offset, 1, ENC_BIG_ENDIAN );
493
8
                if (try_val_to_str(rsn, tn3270_request_vals) == NULL)
494
8
                    break;
495
496
0
                offset++;
497
0
                len--;
498
0
              }
499
8
            }
500
194
            break;
501
3.67k
    }
502
3.66k
    offset++;
503
3.66k
    len--;
504
3.66k
  }
505
506
157
}
507
508
static void
509
dissect_starttls_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, unsigned offset,
510
  unsigned len _U_, proto_tree *tree, proto_item *item _U_)
511
26
{
512
26
  telnet_conv_info_t *session = telnet_get_session(pinfo);
513
514
26
  proto_tree_add_item(tree, hf_telnet_starttls, tvb, offset, 1, ENC_BIG_ENDIAN);
515
516
26
  if (session->starttls_requested_in == 0) {
517
    /* First sender (client or server) requesting to start TLS. */
518
8
    session->starttls_requested_in = pinfo->num;
519
8
    session->starttls_port = pinfo->srcport;
520
18
  } else if (session->starttls_requested_in < pinfo->num &&
521
14
      session->starttls_port != pinfo->srcport) {
522
    /* Other side confirms that following data is TLS. */
523
0
    ssl_starttls_ack(tls_handle, pinfo, telnet_handle);
524
0
  }
525
26
}
526
527
static const value_string telnet_outmark_subopt_cmd_vals[] = {
528
  { '\x06', "ACK" },
529
  { '\x15', "NAK" },
530
  { 'D',    "Default" },
531
  { 'T',    "Top" },
532
  { 'B',    "Bottom" },
533
  { 'L',    "Left" },
534
  { 'R',    "Right" },
535
  { 0, NULL }
536
};
537
538
static void
539
dissect_outmark_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, unsigned offset,
540
  unsigned len, proto_tree *tree, proto_item *item _U_)
541
82
{
542
82
  unsigned    gs_offset, datalen;
543
544
198
  while (len > 0) {
545
116
    proto_tree_add_item(tree, hf_telnet_outmark_subopt_cmd, tvb, offset, 1, ENC_ASCII);
546
547
116
    offset++;
548
116
    len--;
549
550
    /* Look for a GS */
551
116
    if (!tvb_find_uint8_length(tvb, offset, len, 29, &gs_offset)) {
552
      /* None found - run to the end of the packet. */
553
82
      gs_offset = offset + len;
554
82
    }
555
116
    datalen = gs_offset - offset;
556
116
    if (datalen > 0) {
557
65
      proto_tree_add_item(tree, hf_telnet_outmark_subopt_banner, tvb, offset, datalen, ENC_ASCII);
558
65
      offset += datalen;
559
65
      len -= datalen;
560
65
    }
561
116
  }
562
82
}
563
564
static void
565
dissect_htstops_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, unsigned offset, unsigned len,
566
                       proto_tree *tree, proto_item *item)
567
47
{
568
47
  uint8_t cmd;
569
47
  uint8_t tabval;
570
571
47
  cmd = tvb_get_uint8(tvb, offset);
572
47
  switch (cmd) {
573
574
20
  case 0:       /* IS */
575
20
    proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Here's my %s", optname);
576
20
    offset++;
577
20
    len--;
578
20
    break;
579
580
1
  case 1:       /* SEND */
581
1
    proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Send your %s", optname);
582
1
    offset++;
583
1
    len--;
584
1
    break;
585
586
26
  default:
587
26
    expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
588
26
    offset++;
589
26
    len--;
590
26
    if (len > 0)
591
19
      proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
592
26
    return;
593
47
  }
594
595
2.03k
  while (len > 0) {
596
2.01k
    tabval = tvb_get_uint8(tvb, offset);
597
2.01k
    switch (tabval) {
598
599
570
    case 0:
600
570
      proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
601
570
                          tabval, "Sender wants to handle tab stops");
602
570
      break;
603
604
1.25k
    default:
605
1.25k
      proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
606
1.25k
                          tabval, "Sender wants receiver to handle tab stop at %u",
607
1.25k
                          tabval);
608
1.25k
      break;
609
610
3
    case 251:
611
23
    case 252:
612
25
    case 253:
613
46
    case 254:
614
46
      proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
615
46
                          tabval, "Invalid value: %u", tabval);
616
46
      break;
617
618
146
    case 255:
619
146
      proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
620
146
                          tabval, "Sender wants receiver to handle tab stops");
621
146
      break;
622
2.01k
    }
623
2.01k
    offset++;
624
2.01k
    len--;
625
2.01k
  }
626
21
}
627
628
static void
629
dissect_naws_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, unsigned offset,
630
                    unsigned len _U_, proto_tree *tree, proto_item *item _U_)
631
0
{
632
0
  proto_tree_add_item(tree, hf_telnet_naws_subopt_width, tvb, offset, 2, ENC_BIG_ENDIAN);
633
0
  offset += 2;
634
0
  proto_tree_add_item(tree, hf_telnet_naws_subopt_height, tvb, offset, 2, ENC_BIG_ENDIAN);
635
0
}
636
637
/* BEGIN RFC-2217 (COM Port Control) Definitions */
638
639
5
#define TNCOMPORT_SIGNATURE             0
640
2
#define TNCOMPORT_SETBAUDRATE           1
641
91
#define TNCOMPORT_SETDATASIZE           2
642
44
#define TNCOMPORT_SETPARITY             3
643
3
#define TNCOMPORT_SETSTOPSIZE           4
644
4
#define TNCOMPORT_SETCONTROL            5
645
8
#define TNCOMPORT_NOTIFYLINESTATE       6
646
186
#define TNCOMPORT_NOTIFYMODEMSTATE      7
647
10
#define TNCOMPORT_FLOWCONTROLSUSPEND    8
648
11
#define TNCOMPORT_FLOWCONTROLRESUME      9
649
24
#define TNCOMPORT_SETLINESTATEMASK      10
650
544
#define TNCOMPORT_SETMODEMSTATEMASK     11
651
0
#define TNCOMPORT_PURGEDATA             12
652
653
/* END RFC-2217 (COM Port Control) Definitions */
654
655
static void
656
dissect_comport_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, unsigned offset, unsigned len,
657
                       proto_tree *tree, proto_item *item)
658
426
{
659
426
  static const char *datasizes[] = {
660
426
    "Request",
661
426
    "<invalid>",
662
426
    "<invalid>",
663
426
    "<invalid>",
664
426
    "<invalid>",
665
426
    "5",
666
426
    "6",
667
426
    "7",
668
426
    "8"
669
426
  };
670
426
  static const char *parities[] = {
671
426
    "Request",
672
426
    "None",
673
426
    "Odd",
674
426
    "Even",
675
426
    "Mark",
676
426
    "Space"
677
426
  };
678
426
  static const char *stops[] = {
679
426
    "Request",
680
426
    "1",
681
426
    "2",
682
426
    "1.5"
683
426
  };
684
426
  static const char *control[] = {
685
426
    "Output Flow Control Request",
686
426
    "Output Flow: None",
687
426
    "Output Flow: XON/XOFF",
688
426
    "Output Flow: CTS/RTS",
689
426
    "Break Request",
690
426
    "Break: ON",
691
426
    "Break: OFF",
692
426
    "DTR Request",
693
426
    "DTR: ON",
694
426
    "DTR: OFF",
695
426
    "RTS Request",
696
426
    "RTS: ON",
697
426
    "RTS: OFF",
698
426
    "Input Flow Control Request",
699
426
    "Input Flow: None",
700
426
    "Input Flow: XON/XOFF",
701
426
    "Input Flow: CTS/RTS",
702
426
    "Output Flow: DCD",
703
426
    "Input Flow: DTR",
704
426
    "Output Flow: DSR"
705
426
  };
706
426
  static const char *linestate_bits[] = {
707
426
    "Data Ready",
708
426
    "Overrun Error",
709
426
    "Parity Error",
710
426
    "Framing Error",
711
426
    "Break Detected",
712
426
    "Transfer Holding Register Empty",
713
426
    "Transfer Shift Register Empty",
714
426
    "Timeout Error"
715
426
  };
716
426
  static const char *modemstate_bits[] = {
717
426
    "DCTS",
718
426
    "DDSR",
719
426
    "TERI",
720
426
    "DDCD",
721
426
    "CTS",
722
426
    "DSR",
723
426
    "RI",
724
426
    "DCD"
725
426
  };
726
426
  static const char *purges[] = {
727
426
    "Purge None",
728
426
    "Purge RX",
729
426
    "Purge TX",
730
426
    "Purge RX/TX"
731
426
  };
732
733
426
  uint8_t cmd;
734
426
  uint8_t isservercmd;
735
426
  const char *source;
736
737
426
  cmd = tvb_get_uint8(tvb, offset);
738
426
  isservercmd = cmd > 99;
739
426
  cmd = (isservercmd) ? (cmd - 100) : cmd;
740
426
  source = (isservercmd) ? "Server" : "Client";
741
426
  switch (cmd) {
742
5
  case TNCOMPORT_SIGNATURE:
743
5
    len--;
744
5
    if (len == 0) {
745
0
      proto_tree_add_string_format(tree, hf_telnet_comport_subopt_signature, tvb, offset, 1, "", "%s Requests Signature", source);
746
5
    } else {
747
5
      char *sig = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset + 1, len, ENC_ASCII);
748
5
      proto_tree_add_string_format(tree, hf_telnet_comport_subopt_signature, tvb, offset, 1 + len, sig,
749
5
                                         "%s Signature: %s",source, sig);
750
5
    }
751
5
    break;
752
753
2
  case TNCOMPORT_SETBAUDRATE:
754
2
    len--;
755
2
    if (len >= 4) {
756
1
      uint32_t baud = tvb_get_ntohl(tvb, offset+1);
757
1
      if (baud == 0) {
758
0
        proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_baud_rate, tvb, offset, 5, 0, "%s Requests Baud Rate",source);
759
1
      } else {
760
1
        proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_baud_rate, tvb, offset, 5, baud, "%s Baud Rate: %d",source,baud);
761
1
      }
762
1
    } else {
763
1
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_baud_rate, "%s <Invalid Baud Rate Packet>", source);
764
1
    }
765
2
    break;
766
767
91
  case TNCOMPORT_SETDATASIZE:
768
91
    len--;
769
91
    if (len >= 1) {
770
28
      uint8_t datasize = tvb_get_uint8(tvb, offset+1);
771
28
      const char *ds = (datasize > 8) ? "<invalid>" : datasizes[datasize];
772
28
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_data_size, tvb, offset, 2, datasize,
773
28
                                       "%s Data Size: %s",source,ds);
774
63
    } else {
775
63
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_data_size, "%s <Invalid Data Size Packet>", source);
776
63
    }
777
91
    break;
778
779
44
  case TNCOMPORT_SETPARITY:
780
44
    len--;
781
44
    if (len >= 1) {
782
44
      uint8_t parity = tvb_get_uint8(tvb, offset+1);
783
44
      const char *pr = (parity > 5) ? "<invalid>" : parities[parity];
784
44
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_parity, tvb, offset, 2, parity,
785
44
                                       "%s Parity: %s",source,pr);
786
44
    } else {
787
0
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_parity, "%s <Invalid Parity Packet>", source);
788
0
    }
789
44
    break;
790
3
  case TNCOMPORT_SETSTOPSIZE:
791
3
    len--;
792
3
    if (len >= 1) {
793
3
      uint8_t stop = tvb_get_uint8(tvb, offset+1);
794
3
      const char *st = (stop > 3) ? "<invalid>" : stops[stop];
795
3
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_stop, tvb, offset, 2, stop,
796
3
                                       "%s Stop: %s",source,st);
797
3
    } else {
798
0
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_stop, "%s <Invalid Stop Packet>", source);
799
0
    }
800
3
    break;
801
802
4
  case TNCOMPORT_SETCONTROL:
803
4
    len--;
804
4
    if (len >= 1) {
805
4
      uint8_t crt = tvb_get_uint8(tvb, offset+1);
806
4
      const char *c = (crt > 19) ? "Control: <invalid>" : control[crt];
807
4
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_control, tvb, offset, 2, crt,
808
4
                                       "%s Stop: %s",source,c);
809
4
    } else {
810
0
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_control, "%s <Invalid Control Packet>", source);
811
0
    }
812
4
    break;
813
814
8
  case TNCOMPORT_SETLINESTATEMASK:
815
8
  case TNCOMPORT_NOTIFYLINESTATE:
816
8
    len--;
817
8
    if (len >= 1) {
818
8
      const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
819
8
        "%s Set Linestate Mask: %s" : "%s Linestate: %s";
820
8
      int hf_line = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
821
8
        hf_telnet_comport_set_linestate_mask : hf_telnet_comport_linestate;
822
8
      char ls_buffer[512];
823
8
      uint8_t ls = tvb_get_uint8(tvb, offset+1);
824
8
      int print_count = 0;
825
8
      int idx;
826
8
      ls_buffer[0] = '\0';
827
72
      for (idx = 0; idx < 8; idx++) {
828
64
        int bit = ls & 1;
829
64
        if (bit) {
830
21
          if (print_count != 0) {
831
13
            (void) g_strlcat(ls_buffer,", ",512);
832
13
          }
833
21
          (void) g_strlcat(ls_buffer,linestate_bits[idx], 512);
834
21
          print_count++;
835
21
        }
836
64
        ls = ls >> 1;
837
64
      }
838
8
      proto_tree_add_string_format(tree, hf_line, tvb, offset, 2, ls_buffer, print_pattern, source, ls_buffer);
839
8
    } else {
840
0
      const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
841
0
        "%s <Invalid Linestate Mask>" : "%s <Invalid Linestate Packet>";
842
0
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_linestate, print_pattern, source);
843
0
    }
844
8
    break;
845
846
172
  case TNCOMPORT_SETMODEMSTATEMASK:
847
186
  case TNCOMPORT_NOTIFYMODEMSTATE:
848
186
    len--;
849
186
    if (len >= 1) {
850
186
      const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
851
172
        "%s Set Modemstate Mask: %s" : "%s Modemstate: %s";
852
186
      int hf_modem = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
853
172
        hf_telnet_comport_set_modemstate_mask : hf_telnet_comport_modemstate;
854
186
      char ms_buffer[256];
855
186
      uint8_t ms = tvb_get_uint8(tvb, offset+1);
856
186
      int print_count = 0;
857
186
      int idx;
858
186
      ms_buffer[0] = '\0';
859
1.67k
      for (idx = 0; idx < 8; idx++) {
860
1.48k
        int bit = ms & 1;
861
1.48k
        if (bit) {
862
465
          if (print_count != 0) {
863
286
            (void) g_strlcat(ms_buffer,", ",256);
864
286
          }
865
465
          (void) g_strlcat(ms_buffer,modemstate_bits[idx],256);
866
465
          print_count++;
867
465
        }
868
1.48k
        ms = ms >> 1;
869
1.48k
      }
870
186
      proto_tree_add_string_format(tree, hf_modem, tvb, offset, 2, ms_buffer, print_pattern, source, ms_buffer);
871
186
    } else {
872
0
      const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
873
0
        "%s <Invalid Modemstate Mask>" : "%s <Invalid Modemstate Packet>";
874
0
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_modemstate, print_pattern, source);
875
0
    }
876
186
    break;
877
878
10
  case TNCOMPORT_FLOWCONTROLSUSPEND:
879
10
    len--;
880
10
    proto_tree_add_none_format(tree, hf_telnet_comport_subopt_flow_control_suspend, tvb, offset, 1, "%s Flow Control Suspend",source);
881
10
    break;
882
883
11
  case TNCOMPORT_FLOWCONTROLRESUME:
884
11
    len--;
885
11
    proto_tree_add_none_format(tree, hf_telnet_comport_subopt_flow_control_resume, tvb, offset, 1, "%s Flow Control Resume",source);
886
11
    break;
887
888
0
  case TNCOMPORT_PURGEDATA:
889
0
    len--;
890
0
    if (len >= 1) {
891
0
      uint8_t purge = tvb_get_uint8(tvb, offset+1);
892
0
      const char *p = (purge > 3) ? "<Purge invalid>" : purges[purge];
893
0
      proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_purge, tvb, offset, 2, purge,
894
0
                                       "%s %s",source,p);
895
0
    } else {
896
0
      expert_add_info_format(pinfo, item, &ei_telnet_invalid_purge, "%s <Invalid Purge Packet>", source);
897
0
    }
898
0
    break;
899
900
62
  default:
901
62
    expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
902
62
    offset++;
903
62
    len--;
904
62
    if (len > 0)
905
45
      proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
906
62
    return;
907
426
  }
908
909
426
}
910
911
static const value_string rfc_opt_vals[] = {
912
  { 0, "OFF" },
913
  { 1, "ON" },
914
  { 2, "RESTART-ANY" },
915
  { 3, "RESTART-XON" },
916
  { 0, NULL }
917
};
918
919
static void
920
dissect_rfc_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, unsigned offset,
921
                   unsigned len _U_, proto_tree *tree, proto_item *item _U_)
922
0
{
923
0
  proto_tree_add_item(tree, hf_telnet_rfc_subopt_cmd, tvb, offset, 1, ENC_BIG_ENDIAN);
924
0
}
925
926
1
#define TN_ENC_IS               0
927
0
#define TN_ENC_SUPPORT          1
928
1
#define TN_ENC_REPLY            2
929
1
#define TN_ENC_START            3
930
7
#define TN_ENC_END              4
931
0
#define TN_ENC_REQUEST_START    5
932
0
#define TN_ENC_REQUEST_END      6
933
0
#define TN_ENC_ENC_KEYID        7
934
0
#define TN_ENC_DEC_KEYID        8
935
static const value_string enc_cmd_vals[] = {
936
  { TN_ENC_IS,            "IS" },
937
  { TN_ENC_SUPPORT,       "SUPPORT" },
938
  { TN_ENC_REPLY,         "REPLY" },
939
  { TN_ENC_START,         "START" },
940
  { TN_ENC_END,           "END" },
941
  { TN_ENC_REQUEST_START, "REQUEST-START" },
942
  { TN_ENC_REQUEST_END,   "REQUEST-END" },
943
  { TN_ENC_ENC_KEYID,     "ENC_KEYID" },
944
  { TN_ENC_DEC_KEYID,     "DEC_KEYID" },
945
  { 0, NULL }
946
};
947
948
#define TN_ENCTYPE_NULL                 0
949
#define TN_ENCTYPE_DES_CFB64            1
950
#define TN_ENCTYPE_DES_OFB64            2
951
#define TN_ENCTYPE_DES3_CFB64           3
952
#define TN_ENCTYPE_DES3_OFB64           4
953
#define TN_ENCTYPE_CAST5_40_CFB64       8
954
#define TN_ENCTYPE_CAST5_40_OFB64       9
955
#define TN_ENCTYPE_CAST128_CFB64        10
956
#define TN_ENCTYPE_CAST128_OFB64        11
957
static const value_string enc_type_vals[] = {
958
  { TN_ENCTYPE_NULL,                  "NULL" },
959
  { TN_ENCTYPE_DES_CFB64,             "DES_CFB64" },
960
  { TN_ENCTYPE_DES_OFB64,             "DES_OFB64" },
961
  { TN_ENCTYPE_DES3_CFB64,            "DES3_CFB64" },
962
  { TN_ENCTYPE_DES3_OFB64,            "DES3_OFB64" },
963
  { TN_ENCTYPE_CAST5_40_CFB64,        "CAST5_40_CFB64" },
964
  { TN_ENCTYPE_CAST5_40_OFB64,        "CAST5_40_OFB64" },
965
  { TN_ENCTYPE_CAST128_CFB64,         "CAST128_CFB64" },
966
  { TN_ENCTYPE_CAST128_OFB64,         "CAST128_OFB64" },
967
  { 0, NULL }
968
};
969
970
971
40
#define TN_AC_IS        0
972
1
#define TN_AC_SEND      1
973
10
#define TN_AC_REPLY     2
974
0
#define TN_AC_NAME      3
975
static const value_string auth_cmd_vals[] = {
976
  { TN_AC_IS,     "IS" },
977
  { TN_AC_SEND,   "SEND" },
978
  { TN_AC_REPLY,  "REPLY" },
979
  { TN_AC_NAME,   "NAME" },
980
  { 0, NULL }
981
};
982
983
2
#define TN_AT_NULL           0
984
#define TN_AT_KRB4           1
985
3
#define TN_AT_KRB5           2
986
#define TN_AT_SPX            3
987
#define TN_AT_MINK           4
988
#define TN_AT_SRP            5
989
#define TN_AT_RSA            6
990
0
#define TN_AT_SSL            7
991
#define TN_AT_LOKI          10
992
#define TN_AT_SSA           11
993
#define TN_AT_KEA_SJ        12
994
#define TN_AT_KEA_SJ_INTEG  13
995
#define TN_AT_DSS           14
996
#define TN_AT_NTLM          15
997
static const value_string auth_type_vals[] = {
998
  { TN_AT_NULL,         "NULL" },
999
  { TN_AT_KRB4,         "Kerberos v4" },
1000
  { TN_AT_KRB5,         "Kerberos v5" },
1001
  { TN_AT_SPX,          "SPX" },
1002
  { TN_AT_MINK,         "MINK" },
1003
  { TN_AT_SRP,          "SRP" },
1004
  { TN_AT_RSA,          "RSA" },
1005
  { TN_AT_SSL,          "SSL" },
1006
  { TN_AT_LOKI,         "LOKI" },
1007
  { TN_AT_SSA,          "SSA" },
1008
  { TN_AT_KEA_SJ,       "KEA_SJ" },
1009
  { TN_AT_KEA_SJ_INTEG, "KEA_SJ_INTEG" },
1010
  { TN_AT_DSS,          "DSS" },
1011
  { TN_AT_NTLM,         "NTLM" },
1012
  { 0, NULL }
1013
};
1014
static const true_false_string auth_mod_cred_fwd = {
1015
  "Client WILL forward auth creds",
1016
  "Client will NOT forward auth creds"
1017
};
1018
static const true_false_string auth_mod_how = {
1019
  "Mutual authentication",
1020
  "One Way authentication"
1021
};
1022
#define TN_AM_OFF               0x00
1023
#define TN_AM_USING_TELOPT      0x01
1024
#define TN_AM_AFTER_EXCHANGE    0x02
1025
#define TN_AM_RESERVED          0x04
1026
static const value_string auth_mod_enc[] = {
1027
  { TN_AM_OFF,            "Off" },
1028
  { TN_AM_USING_TELOPT,   "Telnet Options" },
1029
  { TN_AM_AFTER_EXCHANGE, "After Exchange" },
1030
  { TN_AM_RESERVED,       "Reserved" },
1031
  { 0, NULL }
1032
};
1033
0
#define TN_KRB5_TYPE_AUTH               0
1034
#define TN_KRB5_TYPE_REJECT             1
1035
#define TN_KRB5_TYPE_ACCEPT             2
1036
3
#define TN_KRB5_TYPE_RESPONSE           3
1037
#define TN_KRB5_TYPE_FORWARD            4
1038
#define TN_KRB5_TYPE_FORWARD_ACCEPT     5
1039
#define TN_KRB5_TYPE_FORWARD_REJECT     6
1040
static const value_string auth_krb5_types[] = {
1041
  { TN_KRB5_TYPE_AUTH,            "Auth" },
1042
  { TN_KRB5_TYPE_REJECT,          "Reject" },
1043
  { TN_KRB5_TYPE_ACCEPT,          "Accept" },
1044
  { TN_KRB5_TYPE_RESPONSE,        "Response" },
1045
  { TN_KRB5_TYPE_FORWARD,         "Forward" },
1046
  { TN_KRB5_TYPE_FORWARD_ACCEPT,  "Forward Accept" },
1047
  { TN_KRB5_TYPE_FORWARD_REJECT,  "Forward Reject" },
1048
  { 0, NULL }
1049
};
1050
static void
1051
dissect_authentication_type_pair(packet_info *pinfo _U_, tvbuff_t *tvb, unsigned offset, proto_tree *tree)
1052
45
{
1053
45
  static int * const auth_mods[] = {
1054
45
    &hf_telnet_auth_mod_enc,
1055
45
    &hf_telnet_auth_mod_cred_fwd,
1056
45
    &hf_telnet_auth_mod_how,
1057
45
    &hf_telnet_auth_mod_who,
1058
45
    NULL
1059
45
  };
1060
1061
45
  proto_tree_add_item(tree, hf_telnet_auth_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1062
45
  proto_tree_add_bitmask_list(tree, tvb, offset+1, 1, auth_mods, ENC_BIG_ENDIAN);
1063
45
}
1064
1065
/* Assume no telnet option subnegotiation exceeds 10 kB (arbitrary limit). */
1066
338
#define MAX_TELNET_OPTION_SUBNEG_LEN 10240
1067
1068
static tvbuff_t *
1069
unescape_and_tvbuffify_telnet_option(packet_info *pinfo, tvbuff_t *tvb, unsigned offset, unsigned len)
1070
338
{
1071
338
  tvbuff_t     *option_subneg_tvb;
1072
338
  uint8_t      *buf;
1073
338
  const uint8_t *spos;
1074
338
  uint8_t      *dpos;
1075
338
  int           skip, l;
1076
1077
338
  if(len >= MAX_TELNET_OPTION_SUBNEG_LEN)
1078
0
    return NULL;
1079
1080
338
  spos = tvb_get_ptr(tvb, offset, len);
1081
338
  const uint8_t *last_src_pos = spos + len - 1;
1082
338
  buf = (uint8_t *)wmem_alloc(pinfo->pool, len);
1083
338
  dpos = buf;
1084
338
  skip = 0;
1085
338
  l = len;
1086
10.4k
  while(l > 0) {
1087
    // XXX Add expert info if spos >= last_src_pos?
1088
10.1k
    if(spos < last_src_pos && (spos[0] == 0xff) && (spos[1] == 0xff)) {
1089
1.44k
      skip++;
1090
1.44k
      l -= 2;
1091
1.44k
      *(dpos++) = 0xff;
1092
1.44k
      spos += 2;
1093
1.44k
      continue;
1094
1.44k
    }
1095
8.70k
    *(dpos++) = *(spos++);
1096
8.70k
    l--;
1097
8.70k
  }
1098
338
  option_subneg_tvb = tvb_new_child_real_data(tvb, buf, len-skip, len-skip);
1099
338
  add_new_data_source(pinfo, option_subneg_tvb, "Unpacked Telnet Option");
1100
1101
338
  return option_subneg_tvb;
1102
338
}
1103
1104
1105
/* as per RFC2942 */
1106
static void
1107
dissect_krb5_authentication_data(packet_info *pinfo, tvbuff_t *tvb, unsigned offset, unsigned len, proto_tree *tree, uint8_t acmd)
1108
3
{
1109
3
  tvbuff_t *krb5_tvb;
1110
3
  uint8_t   krb5_cmd;
1111
1112
3
  krb5_cmd=tvb_get_uint8(tvb, offset);
1113
3
  proto_tree_add_uint(tree, hf_telnet_auth_krb5_type, tvb, offset, 1, krb5_cmd);
1114
3
  offset++;
1115
3
  len--;
1116
1117
1118
  /* IAC SB AUTHENTICATION IS <authentication-type-pair> AUTH <Kerberos V5 KRB_AP_REQ message> IAC SE */
1119
3
  if((acmd==TN_AC_IS)&&(krb5_cmd==TN_KRB5_TYPE_AUTH)){
1120
0
    if(len){
1121
0
      krb5_tvb=tvb_new_subset_length(tvb, offset, len);
1122
0
      dissect_kerberos_main(krb5_tvb, pinfo, tree, false, NULL);
1123
0
    }
1124
0
  }
1125
1126
1127
1128
  /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> ACCEPT IAC SE */
1129
  /* nothing more to dissect */
1130
1131
1132
1133
  /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> REJECT <optional reason for rejection> IAC SE*/
1134
/*qqq*/
1135
1136
1137
  /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> RESPONSE <KRB_AP_REP message> IAC SE */
1138
3
  if((acmd==TN_AC_REPLY)&&(krb5_cmd==TN_KRB5_TYPE_RESPONSE)){
1139
0
    if(len){
1140
0
      krb5_tvb=tvb_new_subset_length(tvb, offset, len);
1141
0
      dissect_kerberos_main(krb5_tvb, pinfo, tree, false, NULL);
1142
0
    }
1143
0
  }
1144
1145
1146
  /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD <KRB_CRED message> IAC SE */
1147
  /* XXX unclear what this one looks like */
1148
1149
1150
  /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_ACCEPT IAC SE */
1151
  /* nothing more to dissect */
1152
1153
1154
1155
  /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_REJECT */
1156
  /* nothing more to dissect */
1157
3
}
1158
1159
1160
#define TN_AUTH_SSL_START  1
1161
0
#define TN_AUTH_SSL_ACCEPT 2
1162
#define TN_AUTH_SSL_REJECT 3
1163
1164
static const value_string ssl_auth_status[] = {
1165
  { TN_AUTH_SSL_START,  "Start" },
1166
  { TN_AUTH_SSL_ACCEPT, "Accepted" },
1167
  { TN_AUTH_SSL_REJECT, "Rejected" },
1168
  { 0, NULL }
1169
};
1170
1171
static void
1172
dissect_ssl_authentication_data(packet_info *pinfo, tvbuff_t *tvb, unsigned offset, proto_tree *tree, uint8_t acmd)
1173
0
{
1174
0
  unsigned ssl_status;
1175
1176
0
  proto_tree_add_item_ret_uint(tree, hf_telnet_auth_ssl_status, tvb, offset, 1, ENC_NA, &ssl_status);
1177
1178
0
  if (acmd == TN_AC_REPLY && ssl_status == TN_AUTH_SSL_ACCEPT)
1179
    /* TLS negotiation will immediately follow this packet. */
1180
0
    ssl_starttls_ack(tls_handle, pinfo, telnet_handle);
1181
0
}
1182
1183
/* as per RFC2941 */
1184
static void
1185
dissect_authentication_data(packet_info *pinfo, tvbuff_t *tvb, unsigned offset, unsigned len, proto_tree *tree, uint8_t acmd)
1186
37
{
1187
37
  uint8_t auth_type;
1188
1189
37
  dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1190
37
  auth_type = tvb_get_uint8(tvb, offset);
1191
37
  offset += 2;
1192
37
  len -= 2;
1193
1194
37
  switch (auth_type) {
1195
2
  case TN_AT_NULL:
1196
2
    break;
1197
1198
0
  case TN_AT_SSL:
1199
0
    dissect_ssl_authentication_data(pinfo, tvb, offset, tree, acmd);
1200
0
    break;
1201
1202
3
  case TN_AT_KRB5:
1203
3
    dissect_krb5_authentication_data(pinfo, tvb, offset, len, tree, acmd);
1204
3
    break;
1205
1206
32
  default:
1207
    /* We don't (yet) know how to dissect the data for this authentication type. */
1208
32
    if (len > 0)
1209
20
      proto_tree_add_bytes_format(tree, hf_telnet_auth_data, tvb, offset, len, NULL, "Unhandled authentication data");
1210
37
  }
1211
37
}
1212
1213
static void
1214
dissect_authentication_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, unsigned offset, unsigned len,
1215
                              proto_tree *tree, proto_item *item _U_)
1216
67
{
1217
67
  uint8_t acmd;
1218
1219
67
  acmd=tvb_get_uint8(tvb, offset);
1220
67
  proto_tree_add_uint(tree, hf_telnet_auth_cmd, tvb, offset, 1, acmd);
1221
67
  offset++;
1222
67
  len--;
1223
1224
67
  switch(acmd){
1225
7
  case TN_AC_REPLY:
1226
37
  case TN_AC_IS:
1227
37
    dissect_authentication_data(pinfo, tvb, offset, len, tree, acmd);
1228
37
    break;
1229
1230
1
  case TN_AC_SEND:
1231
9
    while(len>0){
1232
8
      dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1233
8
      offset+=2;
1234
8
      len-=2;
1235
8
    }
1236
1
    break;
1237
1238
0
  case TN_AC_NAME:
1239
0
    proto_tree_add_item(tree, hf_telnet_auth_name, tvb, offset, len, ENC_ASCII);
1240
0
    break;
1241
67
  }
1242
67
}
1243
1244
/* This function only uses the octet in the buffer at 'offset' */
1245
1
static void dissect_encryption_type(tvbuff_t *tvb, unsigned offset, proto_tree *tree) {
1246
1
  uint8_t etype;
1247
1
  etype = tvb_get_uint8(tvb, offset);
1248
1
  proto_tree_add_uint(tree, hf_telnet_enc_type, tvb, offset, 1, etype);
1249
1
}
1250
1251
static void
1252
dissect_encryption_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, unsigned offset, unsigned len,
1253
                          proto_tree *tree, proto_item *item)
1254
18
{
1255
18
  uint8_t ecmd, key_first_octet;
1256
1257
18
  ecmd = tvb_get_uint8(tvb, offset);
1258
18
  proto_tree_add_uint(tree, hf_telnet_enc_cmd, tvb, offset, 1, ecmd);
1259
1260
18
  offset++;
1261
18
  len--;
1262
1263
18
  switch(ecmd) {
1264
1
  case TN_ENC_IS:
1265
1
  case TN_ENC_REPLY:
1266
    /* encryption type, type-specific data ... */
1267
1
    if (len > 0) {
1268
1
      dissect_encryption_type(tvb, offset, tree);
1269
1
      offset++;
1270
1
      len--;
1271
1
      proto_tree_add_item(tree, hf_telnet_enc_type_data, tvb, offset, len, ENC_NA);
1272
1
    }
1273
1
    break;
1274
1275
0
  case TN_ENC_SUPPORT:
1276
    /* list of encryption types ... */
1277
0
    while (len > 0) {
1278
0
      dissect_encryption_type(tvb, offset, tree);
1279
0
      offset++;
1280
0
      len--;
1281
0
    }
1282
0
    break;
1283
1284
1
  case TN_ENC_START:
1285
    /* keyid ... */
1286
1
    if (len > 0) {
1287
1
      key_first_octet = tvb_get_uint8(tvb, offset);
1288
1
      proto_tree_add_bytes_format(tree, hf_telnet_enc_key_id, tvb, offset, len, NULL, (key_first_octet == 0) ? "Default key" : "Key ID");
1289
1
    }
1290
1
    break;
1291
1292
7
  case TN_ENC_END:
1293
    /* no data */
1294
7
    break;
1295
1296
0
  case TN_ENC_REQUEST_START:
1297
    /* (optional) keyid */
1298
0
    if (len > 0)
1299
0
      proto_tree_add_bytes_format(tree, hf_telnet_enc_key_id, tvb, offset, len, NULL, "Key ID (advisory)");
1300
0
    break;
1301
1302
0
  case TN_ENC_REQUEST_END:
1303
    /* no data */
1304
0
    break;
1305
1306
0
  case TN_ENC_ENC_KEYID:
1307
0
  case TN_ENC_DEC_KEYID:
1308
    /* (optional) keyid - if not supplied, there are no more known keys */
1309
0
    if (len > 0)
1310
0
      proto_tree_add_item(tree, hf_telnet_enc_key_id, tvb, offset, len, ENC_NA);
1311
0
    break;
1312
1313
9
  default:
1314
9
    expert_add_info(pinfo, item, &ei_telnet_enc_cmd_unknown);
1315
18
  }
1316
18
}
1317
1318
586
#define VMWARE_TELNET_EXT 232
1319
1320
/* Option Subnegotiation */
1321
22
#define VMWARE_KNOWN_SUBOPTIONS_1 0
1322
22
#define VMWARE_KNOWN_SUBOPTIONS_2 1
1323
1324
/* Unknown Command Response */
1325
3
#define VMWARE_UNKNOWN_SUBOPTION_RCVD_1 2
1326
9
#define VMWARE_UNKNOWN_SUBOPTION_RCVD_2 3
1327
1328
/* vMotion Notification */
1329
2
#define VMWARE_VMOTION_BEGIN 40
1330
0
#define VMWARE_VMOTION_GOAHEAD 41
1331
2
#define VMWARE_VMOTION_NOTNOW 43
1332
0
#define VMWARE_VMOTION_PEER 44
1333
2
#define VMWARE_VMOTION_PEER_OK 45
1334
2
#define VMWARE_VMOTION_COMPLETE 46
1335
0
#define VMWARE_VMOTION_ABORT 48
1336
1337
/* Proxy operation */
1338
0
#define VMWARE_DO_PROXY 70
1339
1
#define VMWARE_WILL_PROXY 71
1340
1
#define VMWARE_WONT_PROXY 73
1341
1342
/* Virtual machine identification */
1343
0
#define VMWARE_VM_VC_UUID 80
1344
0
#define VMWARE_GET_VM_VC_UUID 81
1345
0
#define VMWARE_VM_NAME 82
1346
0
#define VMWARE_GET_VM_NAME 83
1347
0
#define VMWARE_VM_BIOS_UUID 84
1348
0
#define VMWARE_GET_VM_BIOS_UUID 85
1349
0
#define VMWARE_VM_LOCATION_UUID 86
1350
0
#define VMWARE_GET_VM_LOCATION_UUID 87
1351
1352
static const value_string vmware_cmd_vals[] = {
1353
  { VMWARE_KNOWN_SUBOPTIONS_1,       "KNOWN-SUBOPTIONS-1" },
1354
  { VMWARE_KNOWN_SUBOPTIONS_2,       "KNOWN-SUBOPTIONS-2" },
1355
  { VMWARE_UNKNOWN_SUBOPTION_RCVD_1, "UNKNOWN-SUBOPTION-RCVD-1" },
1356
  { VMWARE_UNKNOWN_SUBOPTION_RCVD_2, "UNKNOWN-SUBOPTION-RCVD-2" },
1357
  { VMWARE_VMOTION_BEGIN,            "VMOTION-BEGIN" },
1358
  { VMWARE_VMOTION_GOAHEAD,          "VMOTION-GOAHEAD" },
1359
  { VMWARE_VMOTION_NOTNOW,           "VMOTION-NOTNOW" },
1360
  { VMWARE_VMOTION_PEER,             "VMOTION-PEER" },
1361
  { VMWARE_VMOTION_PEER_OK,          "VMOTION-PEER-OK" },
1362
  { VMWARE_VMOTION_COMPLETE,         "VMOTION-COMPLETE" },
1363
  { VMWARE_VMOTION_ABORT,            "VMOTION-ABORT" },
1364
  { VMWARE_DO_PROXY,                 "DO-PROXY" },
1365
  { VMWARE_WILL_PROXY,               "WILL-PROXY" },
1366
  { VMWARE_WONT_PROXY,               "WONT-PROXY" },
1367
  { VMWARE_VM_VC_UUID,               "VM-VC-UUID" },
1368
  { VMWARE_GET_VM_VC_UUID,           "GET-VM-VC-UUID" },
1369
  { VMWARE_VM_NAME,                  "VM-NAME" },
1370
  { VMWARE_GET_VM_NAME,              "GET-VM-NAME" },
1371
  { VMWARE_VM_BIOS_UUID,             "VM-BIOS-UUID" },
1372
  { VMWARE_GET_VM_BIOS_UUID,         "GET-VM-BIOS-UUID" },
1373
  { VMWARE_VM_LOCATION_UUID,         "VM-LOCATION-UUID" },
1374
  { VMWARE_GET_VM_LOCATION_UUID,     "GET-VM-LOCATION-UUID" },
1375
  { 0, NULL }
1376
};
1377
1378
/* Encoding for the "direction" argument to DO-PROXY: */
1379
#define VMWARE_PROXY_DIRECTION_CLIENT 'C'
1380
#define VMWARE_PROXY_DIRECTION_SERVER 'S'
1381
1382
static const value_string vmware_proxy_direction_vals[] = {
1383
  { VMWARE_PROXY_DIRECTION_CLIENT, "Client" },
1384
  { VMWARE_PROXY_DIRECTION_SERVER, "Server" },
1385
  { 0, NULL }
1386
};
1387
1388
static void
1389
dissect_vmware_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, unsigned offset, unsigned len,
1390
                      proto_tree *tree, proto_item *item _U_)
1391
43
{
1392
  /*
1393
   * The VMware virtual serial port proxy uses the Telnet protocol over TCP
1394
   * port 13370.  Use "Decode As..." or specify "-d tcp.port==13370,telnet" on
1395
   * the command-line.
1396
   */
1397
1398
43
  uint8_t vmwcmd;
1399
1400
43
  vmwcmd = tvb_get_uint8(tvb, offset);
1401
43
  proto_tree_add_uint(tree, hf_telnet_vmware_cmd, tvb, offset, 1, vmwcmd);
1402
43
  offset++;
1403
43
  len--;
1404
1405
43
  switch (vmwcmd) {
1406
1407
  /* --- Option Subnegotiation --- */
1408
1409
22
  case VMWARE_KNOWN_SUBOPTIONS_1:
1410
22
  case VMWARE_KNOWN_SUBOPTIONS_2:
1411
    /* Data: suboptions... */
1412
1.15k
    while (len > 0) {
1413
1.13k
      proto_tree_add_item(tree, hf_telnet_vmware_known_suboption_code, tvb, offset, 1, ENC_NA);
1414
1.13k
      offset++;
1415
1.13k
      len--;
1416
1.13k
    }
1417
22
    break;
1418
1419
  /* --- Unknown Command Response --- */
1420
1421
3
  case VMWARE_UNKNOWN_SUBOPTION_RCVD_1:
1422
9
  case VMWARE_UNKNOWN_SUBOPTION_RCVD_2:
1423
    /* Data: suboption */
1424
9
    proto_tree_add_item(tree, hf_telnet_vmware_unknown_subopt_code, tvb, offset, 1, ENC_NA);
1425
9
    offset++;
1426
9
    len--;
1427
9
    break;
1428
1429
  /* --- vMotion Notification --- */
1430
1431
2
  case VMWARE_VMOTION_BEGIN:
1432
2
  case VMWARE_VMOTION_NOTNOW:
1433
2
  case VMWARE_VMOTION_PEER_OK:
1434
2
  case VMWARE_VMOTION_COMPLETE: {
1435
    /* Data: sequence */
1436
2
    telnet_conv_info_t *session = telnet_get_session(pinfo);
1437
2
    if (session->vmotion_sequence_len < 0) {
1438
      /*
1439
       * There is nothing which _requires_ that the sequence length be constant
1440
       * throughout a Telnet conversation, but all implementations currently
1441
       * behave that way and here we assume it will be so.  If that changes,
1442
       * subsequent VMOTION-GOAHEAD/VMOTION-PEER messages might be incorrectly
1443
       * dissected, with bytes incorrectly assigned to the sequence or secret
1444
       * fields.  This should not be a big deal.
1445
       */
1446
1
      session->vmotion_sequence_len = len;
1447
1
    }
1448
2
    proto_tree_add_item(tree, hf_telnet_vmware_vmotion_sequence, tvb, offset, len, ENC_NA);
1449
2
    offset += len;
1450
2
    len = 0;
1451
2
  }
1452
2
    break;
1453
1454
0
  case VMWARE_VMOTION_GOAHEAD:
1455
0
  case VMWARE_VMOTION_PEER: {
1456
    /* Data: sequence secret */
1457
0
    telnet_conv_info_t *session = telnet_get_session(pinfo);
1458
1459
    /*
1460
     * The lack of delimiter between "sequence" and "secret" makes dissection
1461
     * challenging.  We need to track the "vMotion conversation", which spans
1462
     * two Telnet conversations with different endpoints.  The vMotion
1463
     * conversation is identified by a blob containing the concatenation of the
1464
     * sequence and secret.
1465
     */
1466
0
    if ((vmwcmd == VMWARE_VMOTION_GOAHEAD && session->vmotion_sequence_len >= 0) ||
1467
0
        (vmwcmd == VMWARE_VMOTION_PEER && session->vmotion_sequence_len < 0)) {
1468
0
      conversation_element_t conv_key[2] = {
1469
0
        {
1470
0
          .type = CE_BLOB,
1471
0
          .blob = {
1472
0
             .val = tvb_memdup(pinfo->pool, tvb, offset, len),
1473
0
             .len = len,
1474
0
          },
1475
0
        },
1476
0
        {
1477
0
          .type = CE_CONVERSATION_TYPE,
1478
0
          .conversation_type_val = CONVERSATION_VSPC_VMOTION,
1479
0
        }
1480
0
      };
1481
0
      conversation_t *vmotion_conv = find_conversation_full(pinfo->num, conv_key);
1482
1483
0
      if (vmwcmd == VMWARE_VMOTION_GOAHEAD && vmotion_conv == NULL) {
1484
        /*
1485
         * We have the full sequence and secret and we know the length of the
1486
         * "sequence" field.  Stash it (or, really, its session) where we can
1487
         * find it later.
1488
         */
1489
0
        vmotion_conv = conversation_new_full(pinfo->num, conv_key);
1490
0
        conversation_add_proto_data(vmotion_conv, proto_telnet, session);
1491
0
      } else if (vmwcmd == VMWARE_VMOTION_PEER && vmotion_conv != NULL) {
1492
        /*
1493
         * Try to find the length of the "sequence" field from the conversation
1494
         * containing the VMOTION-GOAHEAD message.
1495
         */
1496
0
        telnet_conv_info_t const *source_session =
1497
0
          (telnet_conv_info_t const *)conversation_get_proto_data(vmotion_conv, proto_telnet);
1498
1499
0
        if (source_session != NULL) {
1500
0
          session->vmotion_sequence_len = source_session->vmotion_sequence_len;
1501
0
        }
1502
        /* The secret is only used once, so the vMotion conversation ends here. */
1503
0
        vmotion_conv->last_frame = pinfo->num;
1504
0
      }
1505
0
      wmem_free(pinfo->pool, (void *)conv_key[0].blob.val);
1506
0
    }
1507
0
    if (session->vmotion_sequence_len >= 0 && (unsigned)session->vmotion_sequence_len <= len) {
1508
0
      proto_tree_add_item(tree, hf_telnet_vmware_vmotion_sequence, tvb, offset, (unsigned)session->vmotion_sequence_len, ENC_NA);
1509
0
      offset += (unsigned)session->vmotion_sequence_len;
1510
0
      len -= (unsigned)session->vmotion_sequence_len;
1511
1512
0
      proto_tree_add_item(tree, hf_telnet_vmware_vmotion_secret, tvb, offset, len, ENC_NA);
1513
0
      offset += len;
1514
0
      len = 0;
1515
0
    } else {
1516
      /*
1517
       * With no delimiter between "sequence" and "secret", nor any other way
1518
       * of determining the lengths of those fields, we lack the information to
1519
       * be able to dissect this.  Skip it.
1520
       */
1521
0
      offset += len;
1522
0
      len = 0;
1523
0
    }
1524
0
  }
1525
0
    break;
1526
1527
0
  case VMWARE_VMOTION_ABORT:
1528
    /* no data */
1529
0
    break;
1530
1531
  /* --- Proxy Operation --- */
1532
1533
0
  case VMWARE_DO_PROXY:
1534
    /* Data: direction serviceUri */
1535
0
    proto_tree_add_item(tree, hf_telnet_vmware_proxy_direction, tvb, offset, 1, ENC_ASCII);
1536
0
    offset++;
1537
0
    len--;
1538
0
    proto_tree_add_item(tree, hf_telnet_vmware_proxy_serviceUri, tvb, offset, len, ENC_UTF_8);
1539
0
    offset += len;
1540
0
    len = 0;
1541
0
    break;
1542
1543
1
  case VMWARE_WILL_PROXY:
1544
1
  case VMWARE_WONT_PROXY:
1545
    /* no data */
1546
1
    break;
1547
1548
  /* --- Virtual Machine Identification --- */
1549
1550
0
  case VMWARE_GET_VM_VC_UUID:
1551
0
  case VMWARE_GET_VM_NAME:
1552
0
  case VMWARE_GET_VM_BIOS_UUID:
1553
0
  case VMWARE_GET_VM_LOCATION_UUID:
1554
    /* no data */
1555
0
    break;
1556
1557
0
  case VMWARE_VM_NAME:
1558
    /* Data: vm-name */
1559
0
    proto_tree_add_item(tree, hf_telnet_vmware_vm_name, tvb, offset, len, ENC_UTF_8);
1560
0
    offset += len;
1561
0
    len = 0;
1562
0
    break;
1563
1564
0
  case VMWARE_VM_VC_UUID:
1565
    /* Data: vm-uuid */
1566
0
    proto_tree_add_item(tree, hf_telnet_vmware_vm_vc_uuid, tvb, offset, len, ENC_ASCII);
1567
0
    offset += len;
1568
0
    len = 0;
1569
0
    break;
1570
1571
0
  case VMWARE_VM_BIOS_UUID:
1572
    /* Data: vm-uuid */
1573
0
    proto_tree_add_item(tree, hf_telnet_vmware_vm_bios_uuid, tvb, offset, len, ENC_ASCII);
1574
0
    offset += len;
1575
0
    len = 0;
1576
0
    break;
1577
1578
0
  case VMWARE_VM_LOCATION_UUID:
1579
    /* Data: vm-uuid */
1580
0
    proto_tree_add_item(tree, hf_telnet_vmware_vm_location_uuid, tvb, offset, len, ENC_ASCII);
1581
0
    offset += len;
1582
0
    len = 0;
1583
0
    break;
1584
1585
9
  default:
1586
9
    expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, vmwcmd);
1587
9
    if (len > 0)
1588
8
      proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
1589
9
    return;
1590
43
  }
1591
34
  if (len > 0) {
1592
10
    proto_item *pi = proto_tree_add_bytes_format(tree, hf_telnet_subcommand_data, tvb, offset, len, NULL, "Unexpected data");
1593
10
    expert_add_info_format(pinfo, pi, &ei_telnet_vmware_unexp_data, "%u bytes unexpected data", len);
1594
10
  }
1595
34
}
1596
1597
static const tn_opt options[] = {
1598
  {
1599
    "Binary Transmission",                      /* RFC 856 */
1600
    NULL,                                       /* no suboption negotiation */
1601
    NO_LENGTH,
1602
    0,
1603
    NULL
1604
  },
1605
  {
1606
    "Echo",                                     /* RFC 857 */
1607
    NULL,                                       /* no suboption negotiation */
1608
    NO_LENGTH,
1609
    0,
1610
    NULL
1611
  },
1612
  {
1613
    "Reconnection",                             /* DOD Protocol Handbook */
1614
    NULL,
1615
    NO_LENGTH,
1616
    0,
1617
    NULL
1618
  },
1619
  {
1620
    "Suppress Go Ahead",                        /* RFC 858 */
1621
    NULL,                                       /* no suboption negotiation */
1622
    NO_LENGTH,
1623
    0,
1624
    NULL
1625
  },
1626
  {
1627
    "Approx Message Size Negotiation",          /* Ethernet spec(!) */
1628
    NULL,
1629
    NO_LENGTH,
1630
    0,
1631
    NULL
1632
  },
1633
  {
1634
    "Status",                                   /* RFC 859 */
1635
    &ett_status_subopt,
1636
    VARIABLE_LENGTH,
1637
    1,
1638
    NULL                                        /* XXX - fill me in */
1639
  },
1640
  {
1641
    "Timing Mark",                              /* RFC 860 */
1642
    NULL,                                       /* no suboption negotiation */
1643
    NO_LENGTH,
1644
    0,
1645
    NULL
1646
  },
1647
  {
1648
    "Remote Controlled Trans and Echo",         /* RFC 726 */
1649
    &ett_rcte_subopt,
1650
    VARIABLE_LENGTH,
1651
    1,
1652
    NULL                                        /* XXX - fill me in */
1653
  },
1654
  {
1655
    "Output Line Width",                        /* DOD Protocol Handbook */
1656
    &ett_olw_subopt,
1657
    VARIABLE_LENGTH,                            /* XXX - fill me in */
1658
    0,                                          /* XXX - fill me in */
1659
    NULL                                        /* XXX - fill me in */
1660
  },
1661
  {
1662
    "Output Page Size",                         /* DOD Protocol Handbook */
1663
    &ett_ops_subopt,
1664
    VARIABLE_LENGTH,                            /* XXX - fill me in */
1665
    0,                                          /* XXX - fill me in */
1666
    NULL                                        /* XXX - fill me in */
1667
  },
1668
  {
1669
    "Output Carriage-Return Disposition",       /* RFC 652 */
1670
    &ett_crdisp_subopt,
1671
    FIXED_LENGTH,
1672
    2,
1673
    NULL                                        /* XXX - fill me in */
1674
  },
1675
  {
1676
    "Output Horizontal Tab Stops",              /* RFC 653 */
1677
    &ett_htstops_subopt,
1678
    VARIABLE_LENGTH,
1679
    1,
1680
    dissect_htstops_subopt
1681
  },
1682
  {
1683
    "Output Horizontal Tab Disposition",        /* RFC 654 */
1684
    &ett_htdisp_subopt,
1685
    FIXED_LENGTH,
1686
    2,
1687
    NULL                                        /* XXX - fill me in */
1688
  },
1689
  {
1690
    "Output Formfeed Disposition",              /* RFC 655 */
1691
    &ett_ffdisp_subopt,
1692
    FIXED_LENGTH,
1693
    2,
1694
    NULL                                        /* XXX - fill me in */
1695
  },
1696
  {
1697
    "Output Vertical Tabstops",                 /* RFC 656 */
1698
    &ett_vtstops_subopt,
1699
    VARIABLE_LENGTH,
1700
    1,
1701
    NULL                                        /* XXX - fill me in */
1702
  },
1703
  {
1704
    "Output Vertical Tab Disposition",          /* RFC 657 */
1705
    &ett_vtdisp_subopt,
1706
    FIXED_LENGTH,
1707
    2,
1708
    NULL                                        /* XXX - fill me in */
1709
  },
1710
  {
1711
    "Output Linefeed Disposition",              /* RFC 658 */
1712
    &ett_lfdisp_subopt,
1713
    FIXED_LENGTH,
1714
    2,
1715
    NULL                                        /* XXX - fill me in */
1716
  },
1717
  {
1718
    "Extended ASCII",                           /* RFC 698 */
1719
    &ett_extasc_subopt,
1720
    FIXED_LENGTH,
1721
    2,
1722
    NULL                                        /* XXX - fill me in */
1723
  },
1724
  {
1725
    "Logout",                                   /* RFC 727 */
1726
    NULL,                                       /* no suboption negotiation */
1727
    NO_LENGTH,
1728
    0,
1729
    NULL
1730
  },
1731
  {
1732
    "Byte Macro",                               /* RFC 735 */
1733
    &ett_bytemacro_subopt,
1734
    VARIABLE_LENGTH,
1735
    2,
1736
    NULL                                        /* XXX - fill me in */
1737
  },
1738
  {
1739
    "Data Entry Terminal",                      /* RFC 732, RFC 1043 */
1740
    &ett_det_subopt,
1741
    VARIABLE_LENGTH,
1742
    2,
1743
    NULL                                        /* XXX - fill me in */
1744
  },
1745
  {
1746
    "SUPDUP",                                   /* RFC 734, RFC 736 */
1747
    NULL,                                       /* no suboption negotiation */
1748
    NO_LENGTH,
1749
    0,
1750
    NULL
1751
  },
1752
  {
1753
    "SUPDUP Output",                            /* RFC 749 */
1754
    &ett_supdupout_subopt,
1755
    VARIABLE_LENGTH,
1756
    1,
1757
    NULL                                        /* XXX - fill me in */
1758
  },
1759
  {
1760
    "Send Location",                            /* RFC 779 */
1761
    &ett_sendloc_subopt,
1762
    VARIABLE_LENGTH,
1763
    0,
1764
    NULL                                        /* XXX - fill me in */
1765
  },
1766
  {
1767
    "Terminal Type",                            /* RFC 1091 */
1768
    &ett_termtype_subopt,
1769
    VARIABLE_LENGTH,
1770
    1,
1771
    dissect_string_subopt
1772
  },
1773
  {
1774
    "End of Record",                            /* RFC 885 */
1775
    NULL,                                       /* no suboption negotiation */
1776
    NO_LENGTH,
1777
    0,
1778
    NULL
1779
  },
1780
  {
1781
    "TACACS User Identification",               /* RFC 927 */
1782
    &ett_tacacsui_subopt,
1783
    FIXED_LENGTH,
1784
    4,
1785
    NULL                                        /* XXX - fill me in */
1786
  },
1787
  {
1788
    "Output Marking",                           /* RFC 933 */
1789
    &ett_outmark_subopt,
1790
    VARIABLE_LENGTH,
1791
    1,
1792
    dissect_outmark_subopt,
1793
  },
1794
  {
1795
    "Terminal Location Number",                 /* RFC 946 */
1796
    &ett_tlocnum_subopt,
1797
    VARIABLE_LENGTH,
1798
    1,
1799
    NULL                                        /* XXX - fill me in */
1800
  },
1801
  {
1802
    "Telnet 3270 Regime",                       /* RFC 1041 */
1803
    &ett_tn3270reg_subopt,
1804
    VARIABLE_LENGTH,
1805
    1,
1806
    dissect_tn3270_regime_subopt
1807
  },
1808
  {
1809
    "X.3 PAD",                                  /* RFC 1053 */
1810
    &ett_x3pad_subopt,
1811
    VARIABLE_LENGTH,
1812
    1,
1813
    NULL                                        /* XXX - fill me in */
1814
  },
1815
  {
1816
    "Negotiate About Window Size",              /* RFC 1073, DW183 */
1817
    &ett_naws_subopt,
1818
    FIXED_LENGTH,
1819
    4,
1820
    dissect_naws_subopt
1821
  },
1822
  {
1823
    "Terminal Speed",                           /* RFC 1079 */
1824
    &ett_tspeed_subopt,
1825
    VARIABLE_LENGTH,
1826
    1,
1827
    NULL                                        /* XXX - fill me in */
1828
  },
1829
  {
1830
    "Remote Flow Control",                      /* RFC 1372 */
1831
    &ett_rfc_subopt,
1832
    FIXED_LENGTH,
1833
    1,
1834
    dissect_rfc_subopt
1835
  },
1836
  {
1837
    "Linemode",                                 /* RFC 1184 */
1838
    &ett_linemode_subopt,
1839
    VARIABLE_LENGTH,
1840
    1,
1841
    NULL                                        /* XXX - fill me in */
1842
  },
1843
  {
1844
    "X Display Location",                       /* RFC 1096 */
1845
    &ett_xdpyloc_subopt,
1846
    VARIABLE_LENGTH,
1847
    1,
1848
    dissect_string_subopt
1849
  },
1850
  {
1851
    "Environment Option",                       /* RFC 1408, RFC 1571 */
1852
    &ett_env_subopt,
1853
    VARIABLE_LENGTH,
1854
    1,
1855
    NULL                                        /* XXX - fill me in */
1856
  },
1857
  {
1858
    "Authentication Option",                    /* RFC 2941 */
1859
    &ett_auth_subopt,
1860
    VARIABLE_LENGTH,
1861
    1,
1862
    dissect_authentication_subopt
1863
  },
1864
  {
1865
    "Encryption Option",                        /* RFC 2946 */
1866
    &ett_enc_subopt,
1867
    VARIABLE_LENGTH,
1868
    1,
1869
    dissect_encryption_subopt
1870
  },
1871
  {
1872
    "New Environment Option",                   /* RFC 1572 */
1873
    &ett_newenv_subopt,
1874
    VARIABLE_LENGTH,
1875
    1,
1876
    NULL                                        /* XXX - fill me in */
1877
  },
1878
  {
1879
    "TN3270E",                                  /* RFC 1647 */
1880
    &ett_tn3270e_subopt,
1881
    VARIABLE_LENGTH,
1882
    1,
1883
    dissect_tn3270e_subopt
1884
  },
1885
  {
1886
    "XAUTH",                                    /* XAUTH  */
1887
    &ett_xauth_subopt,
1888
    VARIABLE_LENGTH,
1889
    1,
1890
    NULL                                        /* XXX - fill me in */
1891
  },
1892
  {
1893
    "CHARSET",                                  /* CHARSET  */
1894
    &ett_charset_subopt,
1895
    VARIABLE_LENGTH,
1896
    1,
1897
    NULL                                        /* XXX - fill me in */
1898
  },
1899
  {
1900
    "Remote Serial Port",                       /* Remote Serial Port */
1901
    &ett_rsp_subopt,
1902
    VARIABLE_LENGTH,
1903
    1,
1904
    NULL                                        /* XXX - fill me in */
1905
  },
1906
  {
1907
    "COM Port Control",                         /* RFC 2217 */
1908
    &ett_comport_subopt,
1909
    VARIABLE_LENGTH,
1910
    1,
1911
    dissect_comport_subopt
1912
  },
1913
  {
1914
    "Suppress Local Echo",                      /* draft-rfced-exp-atmar-00 */
1915
    NULL,
1916
    NO_LENGTH,
1917
    0,
1918
    NULL
1919
  },
1920
  {
1921
    "Start TLS",                                /* draft-ietf-tn3270e-telnet-tls-06 */
1922
    &ett_starttls_subopt,
1923
    FIXED_LENGTH,
1924
    1,
1925
    dissect_starttls_subopt
1926
  },
1927
  {
1928
    "KERMIT",                                   /* RFC 2840 */
1929
    NULL,
1930
    VARIABLE_LENGTH,
1931
    1,
1932
    NULL                                        /* XXX - stub */
1933
  },
1934
  {
1935
    "SEND-URL",                                 /* draft-croft-telnet-url-trans-00 */
1936
    NULL,
1937
    VARIABLE_LENGTH,
1938
    1,
1939
    NULL                                        /* XXX - stub */
1940
  },
1941
  {
1942
    "FORWARD_X",                                /* draft-altman-telnet-fwdx-03 */
1943
    NULL,
1944
    VARIABLE_LENGTH,
1945
    1,
1946
    NULL                                        /* XXX - stub */
1947
  }
1948
1949
};
1950
1951
static const tn_opt telnet_opt_vmware = {
1952
  "VMware Virtual Serial Port Proxy",
1953
  NULL,
1954
  VARIABLE_LENGTH,
1955
  1,
1956
  dissect_vmware_subopt
1957
};
1958
1959
static const tn_opt telnet_opt_unknown = {
1960
  "<unknown option>",
1961
  NULL,
1962
  VARIABLE_LENGTH,
1963
  0,
1964
  NULL
1965
};
1966
1967
static const tn_opt *
1968
telnet_find_option(uint8_t opt_byte)
1969
2.92k
{
1970
2.92k
  if (opt_byte < array_length(options))
1971
2.33k
    return &options[opt_byte];
1972
1973
586
  if (opt_byte == VMWARE_TELNET_EXT)
1974
86
    return &telnet_opt_vmware;
1975
1976
500
  return &telnet_opt_unknown;
1977
586
}
1978
1979
static int
1980
telnet_sub_option(packet_info *pinfo, proto_tree *option_tree, proto_item *option_item, tvbuff_t *tvb, unsigned start_offset)
1981
1.23k
{
1982
1.23k
  unsigned      offset = start_offset;
1983
1.23k
  uint8_t       opt_byte;
1984
1.23k
  const tn_opt *opt;
1985
1.23k
  unsigned      subneg_len;
1986
1.23k
  unsigned      iac_offset;
1987
1.23k
  unsigned      len;
1988
1.23k
  tvbuff_t     *unescaped_tvb;
1989
1.23k
  unsigned      cur_offset;
1990
1.23k
  bool          iac_found;
1991
1992
  /*
1993
   * As data with value iac (0xff) is possible, this value must be escaped
1994
   * with iac (rfc 854).
1995
   */
1996
1.23k
  unsigned  iac_data = 0;
1997
1998
1.23k
  offset += 2;  /* skip IAC and SB */
1999
2000
  /* Get the option code */
2001
1.23k
  opt_byte = tvb_get_uint8(tvb, offset);
2002
1.23k
  opt = telnet_find_option(opt_byte);
2003
1.23k
  offset++;
2004
2005
  /* Search for an unescaped IAC. */
2006
1.23k
  cur_offset = offset;
2007
1.23k
  len = tvb_reported_length_remaining(tvb, offset);
2008
2.71k
  do {
2009
2.71k
    iac_found = tvb_find_uint8_length(tvb, cur_offset, len, TN_IAC, &iac_offset);
2010
2.71k
    if (iac_found == false) {
2011
      /* None found - run to the end of the packet. */
2012
43
      offset += len;
2013
      /* To exit loop ?? (to keep logic from tvb_find_uint8())*/
2014
43
      iac_found = true;
2015
2.67k
    } else {
2016
2.67k
      if (!tvb_offset_exists(tvb, iac_offset + 1) ||
2017
2.65k
          (tvb_get_uint8(tvb, iac_offset + 1) != TN_IAC)) {
2018
        /* We really found a single IAC, so we're done */
2019
1.19k
        offset = iac_offset;
2020
1.47k
      } else {
2021
        /*
2022
         * We saw an escaped IAC, so we have to move ahead to the
2023
         * next section
2024
         */
2025
1.47k
        iac_found = false;
2026
1.47k
        cur_offset = iac_offset + 2;
2027
1.47k
        iac_data += 1;
2028
1.47k
      }
2029
2.67k
    }
2030
2031
2.71k
  } while (!iac_found);
2032
2033
1.23k
  subneg_len = offset - start_offset;
2034
2035
1.23k
  start_offset += 3;    /* skip IAC, SB, and option code */
2036
1.23k
  subneg_len -= 3;
2037
2038
1.23k
  if (subneg_len > 0) {
2039
2040
    /* Now dissect the suboption parameters. */
2041
1.19k
    if (opt->dissect != NULL) {
2042
2043
1.07k
      switch (opt->len_type) {
2044
2045
0
      case NO_LENGTH:
2046
        /* There isn't supposed to *be* sub-option negotiation for this. */
2047
0
        expert_add_info_format(pinfo, option_item, &ei_telnet_suboption_length, "Bogus suboption data");
2048
0
        return offset;
2049
2050
159
      case FIXED_LENGTH:
2051
        /* Make sure the length is what it's supposed to be. */
2052
159
        if (subneg_len - iac_data != opt->optlen) {
2053
133
          expert_add_info_format(pinfo, option_item, &ei_telnet_suboption_length, "Suboption parameter length is %d, should be %d", subneg_len, opt->optlen);
2054
133
          return offset;
2055
133
        }
2056
26
        break;
2057
2058
912
      case VARIABLE_LENGTH:
2059
        /* Make sure the length is greater than the minimum. */
2060
912
        if (subneg_len - iac_data < opt->optlen) {
2061
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);
2062
0
          return offset;
2063
0
        }
2064
912
        break;
2065
1.07k
      }
2066
2067
      /* We have a dissector for this suboption's parameters; call it. */
2068
938
      if (iac_data > 0) {
2069
        /* Data is escaped, we have to unescape it. */
2070
293
        unescaped_tvb = unescape_and_tvbuffify_telnet_option(pinfo, tvb, start_offset, subneg_len);
2071
293
        (*opt->dissect)(pinfo, opt->name, unescaped_tvb, 0, subneg_len - iac_data, option_tree, option_item);
2072
645
      } else {
2073
645
        (*opt->dissect)(pinfo, opt->name, tvb, start_offset, subneg_len, option_tree, option_item);
2074
645
      }
2075
938
    } else {
2076
      /* We don't have a dissector for them; just show them as data. */
2077
120
      if (iac_data > 0) {
2078
        /* Data is escaped, we have to unescape it. */
2079
45
        unescaped_tvb = unescape_and_tvbuffify_telnet_option(pinfo, tvb, start_offset, subneg_len);
2080
45
        proto_tree_add_item(option_tree, hf_telnet_option_data, unescaped_tvb, 0, subneg_len - iac_data, ENC_NA);
2081
75
      } else {
2082
75
        proto_tree_add_item(option_tree, hf_telnet_option_data, tvb, start_offset, subneg_len, ENC_NA);
2083
75
      }
2084
120
    }
2085
1.19k
  }
2086
1.10k
  return offset;
2087
1.23k
}
2088
2089
static void
2090
telnet_suboption_name(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int* offset, const char** optname,
2091
                      proto_tree **opt_tree, proto_item **opt_item, const char *type)
2092
1.68k
{
2093
1.68k
  uint8_t       opt_byte;
2094
1.68k
  const tn_opt *opt;
2095
1.68k
  int           ett = ett_telnet_subopt;
2096
2097
1.68k
  opt_byte = tvb_get_uint8(tvb, *offset);
2098
1.68k
  opt = telnet_find_option(opt_byte);
2099
1.68k
  if (opt->subtree_index != NULL)
2100
1.07k
    ett = *(opt->subtree_index);
2101
1.68k
  *opt_item = proto_tree_add_uint_format_value(tree, hf_telnet_subcmd, tvb, *offset, 1, opt_byte, "%s", opt->name);
2102
1.68k
  *opt_tree = proto_item_add_subtree(*opt_item, ett);
2103
2104
1.68k
  (*offset)++;
2105
1.68k
  (*optname) = wmem_strdup_printf(pinfo->pool, "%s %s", type, opt->name);
2106
1.68k
}
2107
2108
static int
2109
telnet_command(packet_info *pinfo, proto_tree *telnet_tree, tvbuff_t *tvb, int start_offset, unsigned *num_info_items)
2110
4.84k
{
2111
4.84k
  int    offset = start_offset;
2112
4.84k
  unsigned char optcode;
2113
4.84k
  const char* optname;
2114
4.84k
  proto_item *cmd_item, *subopt_item = NULL;
2115
4.84k
  proto_tree *cmd_tree, *subopt_tree = NULL;
2116
2117
4.84k
  offset += 1;  /* skip IAC */
2118
4.84k
  optcode = tvb_get_uint8(tvb, offset);
2119
2120
4.84k
  cmd_tree = proto_tree_add_subtree(telnet_tree, tvb, start_offset, 2, ett_telnet_cmd, &cmd_item, "Command header");
2121
4.84k
  proto_tree_add_item(cmd_tree, hf_telnet_cmd, tvb, offset, 1, ENC_BIG_ENDIAN);
2122
4.84k
  offset++;
2123
2124
4.84k
  switch(optcode) {
2125
56
  case TN_WILL:
2126
56
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Will");
2127
56
    break;
2128
2129
94
  case TN_WONT:
2130
94
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Won't");
2131
94
    break;
2132
2133
96
  case TN_DO:
2134
96
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Do");
2135
96
    break;
2136
2137
200
  case TN_DONT:
2138
200
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Don't");
2139
200
    break;
2140
2141
1.24k
  case TN_SB:
2142
1.24k
    telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Suboption");
2143
1.24k
    break;
2144
2145
2.97k
  default:
2146
2.97k
    optname = val_to_str_const(optcode, cmd_vals, "<unknown option>");
2147
2.97k
    break;
2148
4.84k
  }
2149
2150
4.65k
  proto_item_set_text(cmd_item, "%s", optname);
2151
4.65k
  if (optcode != TN_SE) {
2152
4.61k
    add_telnet_info_str(pinfo, num_info_items, optname);
2153
4.61k
  }
2154
2155
4.65k
  if (optcode == TN_SB) {
2156
1.23k
    offset = telnet_sub_option(pinfo, subopt_tree, subopt_item, tvb, start_offset);
2157
1.23k
  }
2158
2159
4.65k
  proto_item_set_len(cmd_item, offset-start_offset);
2160
2161
4.65k
  return offset;
2162
4.84k
}
2163
2164
static void
2165
telnet_add_text(proto_tree *tree, tvbuff_t *tvb, unsigned offset, unsigned len)
2166
2.51k
{
2167
2.51k
  unsigned next_offset;
2168
2.51k
  unsigned linelen;
2169
2.51k
  uint8_t  c;
2170
2.51k
  bool last_char_was_cr;
2171
2172
5.68k
  while (len != 0 && tvb_offset_exists(tvb, offset)) {
2173
    /*
2174
     * Find the end of the line.
2175
     */
2176
3.16k
    tvb_find_line_end_length(tvb, offset, len, &linelen, &next_offset);
2177
3.16k
    len -= next_offset - offset;        /* subtract out the line's characters */
2178
2179
    /*
2180
     * In Telnet, CR NUL is the way you send a CR by itself in the
2181
     * default ASCII mode; don't treat CR by itself as a line ending,
2182
     * treat only CR NUL, CR LF, or LF by itself as a line ending.
2183
     */
2184
3.16k
    if (next_offset == offset + linelen + 1 && len >= 1) {
2185
      /*
2186
       * Well, we saw a one-character line ending, so either it's a CR
2187
       * or an LF; we have at least two characters left, including the
2188
       * CR.
2189
       *
2190
       * If the line ending is a CR, skip all subsequent CRs; at
2191
       * least one capture appeared to have multiple CRs at the end of
2192
       * a line.
2193
       */
2194
719
      if (tvb_get_uint8(tvb, offset + linelen) == '\r') {
2195
203
        last_char_was_cr = true;
2196
2.86k
        while (len != 0 && tvb_offset_exists(tvb, next_offset)) {
2197
2.76k
          c = tvb_get_uint8(tvb, next_offset);
2198
2.76k
          next_offset++;        /* skip over that character */
2199
2.76k
          len--;
2200
2.76k
          if (c == '\n' || (c == '\0' && last_char_was_cr)) {
2201
            /*
2202
             * LF is a line ending, whether preceded by CR or not.
2203
             * NUL is a line ending if preceded by CR.
2204
             */
2205
99
            break;
2206
99
          }
2207
2.66k
          last_char_was_cr = (c == '\r');
2208
2.66k
        }
2209
203
      }
2210
719
    }
2211
2212
    /*
2213
     * Now compute the length of the line *including* the end-of-line
2214
     * indication, if any; we display it all.
2215
     */
2216
3.16k
    linelen = next_offset - offset;
2217
2218
3.16k
    proto_tree_add_item(tree, hf_telnet_data, tvb, offset, linelen, ENC_ASCII);
2219
3.16k
    offset = next_offset;
2220
3.16k
  }
2221
2.51k
}
2222
2223
static unsigned
2224
find_unescaped_iac(tvbuff_t *tvb, unsigned offset, unsigned len)
2225
4.87k
{
2226
4.87k
  unsigned 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
8.16k
  while ((tvb_find_uint8_length(tvb, iac_offset, len, TN_IAC, &iac_offset)) &&
2231
7.98k
         (tvb_get_uint8(tvb, iac_offset + 1) == TN_IAC))
2232
3.28k
  {
2233
3.28k
    iac_offset+=2;
2234
3.28k
    len = tvb_reported_length_remaining(tvb, iac_offset);
2235
3.28k
  }
2236
4.87k
  return iac_offset;
2237
4.87k
}
2238
2239
static int
2240
dissect_telnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2241
277
{
2242
277
  proto_tree *telnet_tree, *ti;
2243
277
  tvbuff_t   *next_tvb;
2244
277
  int         offset    = 0;
2245
277
  unsigned    len       = 0;
2246
277
  unsigned    is_tn3270 = 0;
2247
277
  unsigned    is_tn5250 = 0;
2248
277
  int         data_len;
2249
277
  int         iac_offset;
2250
277
  unsigned    num_info_items = 0;
2251
2252
277
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "TELNET");
2253
277
  col_set_str(pinfo->cinfo, COL_INFO, "Telnet Data" UTF8_HORIZONTAL_ELLIPSIS);
2254
2255
277
  is_tn3270 = find_tn3270_conversation(pinfo);
2256
277
  is_tn5250 = find_tn5250_conversation(pinfo);
2257
2258
277
  ti = proto_tree_add_item(tree, proto_telnet, tvb, offset, -1, ENC_NA);
2259
277
  telnet_tree = proto_item_add_subtree(ti, ett_telnet);
2260
2261
  /*
2262
   * Scan through the buffer looking for an IAC byte.
2263
   */
2264
5.13k
  while ((len = tvb_reported_length_remaining(tvb, offset)) > 0) {
2265
4.87k
    iac_offset = find_unescaped_iac(tvb, offset, len);
2266
4.87k
    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
4.85k
      data_len = iac_offset - offset;
2273
4.85k
      if (data_len > 0) {
2274
3.33k
        add_telnet_data_bytes_str(pinfo, &num_info_items, data_len);
2275
3.33k
        if (is_tn3270) {
2276
815
          next_tvb = tvb_new_subset_length(tvb, offset, data_len);
2277
815
          call_dissector(tn3270_handle, next_tvb, pinfo, telnet_tree);
2278
2.51k
        } 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
2.51k
          telnet_add_text(telnet_tree, tvb, offset, data_len);
2283
3.33k
      }
2284
      /*
2285
       * Now interpret the command.
2286
       */
2287
4.85k
      offset = telnet_command(pinfo, telnet_tree, tvb, iac_offset, &num_info_items);
2288
4.85k
    } else {
2289
      /* get more data if tn3270 */
2290
26
      if (is_tn3270 || is_tn5250) {
2291
0
        pinfo->desegment_offset = offset;
2292
0
        pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
2293
0
        return tvb_captured_length(tvb);
2294
0
      }
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
26
      if (len > 0) {
2301
0
        add_telnet_data_bytes_str(pinfo, &num_info_items, len);
2302
0
        telnet_add_text(telnet_tree, tvb, offset, len);
2303
0
      }
2304
26
      break;
2305
26
    }
2306
4.87k
  }
2307
277
  return tvb_captured_length(tvb);
2308
277
}
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
 */