Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-telnet.c
blob13a8e850f706f91d36c158b96948bca186972062
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>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
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
15 #include "config.h"
17 #include <stdlib.h>
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"
32 void proto_reg_handoff_telnet(void);
33 void proto_register_telnet(void);
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;
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;
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;
75 static int hf_telnet_data;
76 static int hf_telnet_option_data;
77 static int hf_telnet_subcommand_data;
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;
88 static int hf_telnet_starttls;
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;
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;
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;
156 static dissector_handle_t telnet_handle;
158 static dissector_handle_t tn3270_handle;
159 static dissector_handle_t tn5250_handle;
160 static dissector_handle_t tls_handle;
162 /* Some defines for Telnet */
164 #define TCP_PORT_TELNET 23
166 #define TN_IAC 255
167 #define TN_DONT 254
168 #define TN_DO 253
169 #define TN_WONT 252
170 #define TN_WILL 251
171 #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 #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
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 }
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;
217 /* Member of table of IP or TCP options. */
218 typedef struct tn_opt {
219 const char *name; /* name of option */
220 int *subtree_index; /* pointer to subtree index for option */
221 tn_opt_len_type len_type; /* type of option length field */
222 int optlen; /* value length should be (minimum if VARIABLE) */
223 void (*dissect)(packet_info *pinfo, const char *, tvbuff_t *, int, int, proto_tree *, proto_item*);
224 /* routine to dissect option */
225 } tn_opt;
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;
233 static void
234 check_tn3270_model(packet_info *pinfo _U_, const char *terminaltype)
236 int model;
238 if ((strcmp(terminaltype,"IBM-3278-2-E") == 0) || (strcmp(terminaltype,"IBM-3278-2") == 0) ||
239 (strcmp(terminaltype,"IBM-3278-3") == 0) || (strcmp(terminaltype,"IBM-3278-4") == 0) ||
240 (strcmp(terminaltype,"IBM-3278-5") == 0) || (strcmp(terminaltype,"IBM-3277-2") == 0) ||
241 (strcmp(terminaltype,"IBM-3279-3") == 0) || (strcmp(terminaltype,"IBM-3279-4") == 0) ||
242 (strcmp(terminaltype,"IBM-3279-2-E") == 0) || (strcmp(terminaltype,"IBM-3279-2") == 0) ||
243 (strcmp(terminaltype,"IBM-3279-4-E") == 0)) {
244 model = terminaltype[9] - '0';
245 add_tn3270_conversation(pinfo, 0, model);
249 static void
250 check_for_tn3270(packet_info *pinfo _U_, const char *optname, const char *terminaltype)
252 if (strcmp(optname,"Terminal Type") != 0) {
253 return;
255 check_tn3270_model(pinfo, terminaltype);
257 if ((strcmp(terminaltype,"IBM-5555-C01") == 0) || /* 24 x 80 Double-Byte Character Set color display */
258 (strcmp(terminaltype,"IBM-5555-B01") == 0) || /* 24 x 80 Double-Byte Character Set (DBCS)*/
259 (strcmp(terminaltype,"IBM-3477-FC") == 0) || /* 27 x 132 color display*/
260 (strcmp(terminaltype,"IBM-3477-FG") == 0) || /* 27 x 132 monochrome display*/
261 (strcmp(terminaltype,"IBM-3180-2") == 0) || /* 27 x 132 monochrome display*/
262 (strcmp(terminaltype,"IBM-3179-2") == 0) || /* 24 x 80 color display*/
263 (strcmp(terminaltype,"IBM-3196-A1") == 0) || /* 24 x 80 monochrome display*/
264 (strcmp(terminaltype,"IBM-5292-2") == 0) || /* 24 x 80 color display*/
265 (strcmp(terminaltype,"IBM-5291-1") == 0) || /* 24 x 80 monochrome display*/
266 (strcmp(terminaltype,"IBM-5251-11") == 0)) /* 24 x 80 monochrome display*/
267 add_tn5250_conversation(pinfo, 0);
270 static telnet_conv_info_t *
271 telnet_get_session(packet_info *pinfo)
273 conversation_t *conversation = find_or_create_conversation(pinfo);
274 telnet_conv_info_t *telnet_info;
276 telnet_info = (telnet_conv_info_t*)conversation_get_proto_data(conversation, proto_telnet);
277 if (!telnet_info) {
278 telnet_info = wmem_new0(wmem_file_scope(), telnet_conv_info_t);
279 telnet_info->vmotion_sequence_len = -1;
280 conversation_add_proto_data(conversation, proto_telnet, telnet_info);
282 return telnet_info;
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)
289 const unsigned max_info_items = 5; /* Arbitrary limit so the column doesn't end up too wide. */
291 if (*num_items == 0) {
292 /* Replace the default info text. */
293 col_add_str(pinfo->cinfo, COL_INFO, str);
294 } else if (*num_items < max_info_items) {
295 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, str);
296 } else if (*num_items == max_info_items) {
297 /* Too many to display. Finish with an ellipsis. */
298 col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, UTF8_HORIZONTAL_ELLIPSIS);
300 (*num_items)++;
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)
307 char str[30];
309 snprintf(str, sizeof str, "%u byte%s data", len, plurality(len, "", "s"));
310 add_telnet_info_str(pinfo, num_items, str);
313 static void
314 dissect_string_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, int offset, int len,
315 proto_tree *tree, proto_item *item)
317 uint8_t cmd;
319 cmd = tvb_get_uint8(tvb, offset);
320 switch (cmd) {
322 case 0: /* IS */
323 proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Here's my %s", optname);
324 offset++;
325 len--;
326 if (len > 0) {
327 proto_tree_add_item(tree, hf_telnet_string_subopt_value, tvb, offset, len, ENC_NA|ENC_ASCII);
329 check_for_tn3270(pinfo, optname, tvb_format_text(pinfo->pool, tvb, offset, len));
330 break;
332 case 1: /* SEND */
333 proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Send your %s", optname);
334 offset++;
335 len--;
336 if (len > 0)
337 proto_tree_add_bytes_format(tree, hf_telnet_subcommand_data, tvb, offset, len, NULL, "Extra data");
338 break;
340 default:
341 expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
343 offset++;
344 len--;
345 if (len > 0)
346 proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
347 break;
351 static void
352 dissect_tn3270_regime_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, int offset,
353 int len, proto_tree *tree, proto_item *item _U_)
355 #define TN3270_REGIME_ARE 0x01
356 #define TN3270_REGIME_IS 0x00
358 uint8_t cmd;
360 while (len > 0) {
361 cmd = tvb_get_uint8(tvb, offset);
362 switch (cmd) {
363 case TN3270_REGIME_ARE:
364 case TN3270_REGIME_IS:
365 if (cmd == TN3270_REGIME_ARE) {
366 proto_tree_add_uint_format(tree, hf_tn3270_regime_cmd, tvb, offset, 1, cmd, "ARE");
367 add_tn3270_conversation(pinfo, 0, 0);
368 } else {
369 proto_tree_add_uint_format(tree, hf_tn3270_regime_cmd, tvb, offset, 1, cmd, "IS");
371 proto_tree_add_item(tree, hf_tn3270_regime_subopt_value, tvb, offset + 1, len - 1, ENC_NA|ENC_ASCII);
372 return;
373 default:
374 proto_tree_add_uint_format(tree, hf_tn3270_regime_cmd, tvb, offset, 1, cmd, "Bogus value: %u", cmd);
375 break;
377 offset++;
378 len --;
383 #define TN3270_ASSOCIATE 0x00
384 #define TN3270_CONNECT 0x01
385 #define TN3270_DEVICE_TYPE 0x02
386 #define TN3270_FUNCTIONS 0x03
387 #define TN3270_IS 0x04
388 #define TN3270_REASON 0x05
389 #define TN3270_REJECT 0x06
390 #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
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 }
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 }
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 }
442 static void
443 dissect_tn3270e_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
444 int len, proto_tree *tree, proto_item *item _U_)
447 uint8_t cmd;
448 int datalen;
449 int connect_offset = 0;
450 int device_type = 0;
451 int rsn = 0;
453 while (len > 0) {
454 cmd = tvb_get_uint8(tvb, offset);
455 proto_tree_add_item( tree, hf_tn3270_subopt, tvb, offset, 1, ENC_BIG_ENDIAN );
456 switch (cmd) {
457 case TN3270_CONNECT:
458 proto_tree_add_item( tree, hf_tn3270_connect, tvb, offset + 1, len, ENC_NA|ENC_ASCII );
459 offset += (len - 1);
460 len -= (len - 1);
461 break;
462 case TN3270_IS:
463 device_type = tvb_get_uint8(tvb, offset-1);
464 if (device_type == TN3270_DEVICE_TYPE) {
465 /* If there is a terminal type to display, then it will be followed by CONNECT */
466 connect_offset = tvb_find_uint8(tvb, offset + 1, len, TN3270_CONNECT);
467 if (connect_offset != -1) {
468 datalen = connect_offset - (offset + 1);
469 if (datalen > 0) {
470 proto_tree_add_item( tree, hf_tn3270_is, tvb, offset + 1, datalen, ENC_NA|ENC_ASCII );
471 check_tn3270_model(pinfo, tvb_format_text(pinfo->pool, tvb, offset + 1, datalen));
472 offset += datalen;
473 len -= datalen;
477 break;
478 case TN3270_REASON:
479 offset++;
480 len--;
481 proto_tree_add_item( tree, hf_tn3270_reason, tvb, offset, 1, ENC_BIG_ENDIAN );
482 break;
483 case TN3270_REQUEST:
484 add_tn3270_conversation(pinfo, 1, 0);
485 device_type = tvb_get_uint8(tvb, offset-1);
486 if (device_type == TN3270_DEVICE_TYPE) {
487 proto_tree_add_item( tree, hf_tn3270_request_string, tvb, offset + 1, len-1, ENC_NA|ENC_ASCII );
488 offset += (len - 1);
489 len -= (len - 1);
490 }else if (device_type == TN3270_FUNCTIONS) {
491 while (len > 0) {
492 rsn = tvb_get_uint8(tvb, offset);
493 proto_tree_add_item( tree, hf_tn3270_request, tvb, offset, 1, ENC_BIG_ENDIAN );
494 if (try_val_to_str(rsn, tn3270_request_vals) == NULL)
495 break;
497 offset++;
498 len--;
501 break;
503 offset++;
504 len--;
509 static void
510 dissect_starttls_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
511 int len _U_, proto_tree *tree, proto_item *item _U_)
513 telnet_conv_info_t *session = telnet_get_session(pinfo);
515 proto_tree_add_item(tree, hf_telnet_starttls, tvb, offset, 1, ENC_BIG_ENDIAN);
517 if (session->starttls_requested_in == 0) {
518 /* First sender (client or server) requesting to start TLS. */
519 session->starttls_requested_in = pinfo->num;
520 session->starttls_port = pinfo->srcport;
521 } else if (session->starttls_requested_in < pinfo->num &&
522 session->starttls_port != pinfo->srcport) {
523 /* Other side confirms that following data is TLS. */
524 ssl_starttls_ack(tls_handle, pinfo, telnet_handle);
528 static const value_string telnet_outmark_subopt_cmd_vals[] = {
529 { '\x06', "ACK" },
530 { '\x15', "NAK" },
531 { 'D', "Default" },
532 { 'T', "Top" },
533 { 'B', "Bottom" },
534 { 'L', "Left" },
535 { 'R', "Right" },
536 { 0, NULL }
539 static void
540 dissect_outmark_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
541 int len, proto_tree *tree, proto_item *item _U_)
543 int gs_offset, datalen;
545 while (len > 0) {
546 proto_tree_add_item(tree, hf_telnet_outmark_subopt_cmd, tvb, offset, 1, ENC_ASCII | ENC_NA);
548 offset++;
549 len--;
551 /* Look for a GS */
552 gs_offset = tvb_find_uint8(tvb, offset, len, 29);
553 if (gs_offset == -1) {
554 /* None found - run to the end of the packet. */
555 gs_offset = offset + len;
557 datalen = gs_offset - offset;
558 if (datalen > 0) {
559 proto_tree_add_item(tree, hf_telnet_outmark_subopt_banner, tvb, offset, datalen, ENC_NA|ENC_ASCII);
560 offset += datalen;
561 len -= datalen;
566 static void
567 dissect_htstops_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, int offset, int len,
568 proto_tree *tree, proto_item *item)
570 uint8_t cmd;
571 uint8_t tabval;
573 cmd = tvb_get_uint8(tvb, offset);
574 switch (cmd) {
576 case 0: /* IS */
577 proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Here's my %s", optname);
578 offset++;
579 len--;
580 break;
582 case 1: /* SEND */
583 proto_tree_add_uint_format(tree, hf_telnet_subcmd, tvb, offset, 1, cmd, "Send your %s", optname);
584 offset++;
585 len--;
586 break;
588 default:
589 expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
590 offset++;
591 len--;
592 if (len > 0)
593 proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
594 return;
597 while (len > 0) {
598 tabval = tvb_get_uint8(tvb, offset);
599 switch (tabval) {
601 case 0:
602 proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
603 tabval, "Sender wants to handle tab stops");
604 break;
606 default:
607 proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
608 tabval, "Sender wants receiver to handle tab stop at %u",
609 tabval);
610 break;
612 case 251:
613 case 252:
614 case 253:
615 case 254:
616 proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
617 tabval, "Invalid value: %u", tabval);
618 break;
620 case 255:
621 proto_tree_add_uint_format(tree, hf_telnet_tabstop, tvb, offset, 1,
622 tabval, "Sender wants receiver to handle tab stops");
623 break;
625 offset++;
626 len--;
630 static void
631 dissect_naws_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
632 int len _U_, proto_tree *tree, proto_item *item _U_)
634 proto_tree_add_item(tree, hf_telnet_naws_subopt_width, tvb, offset, 2, ENC_BIG_ENDIAN);
635 offset += 2;
636 proto_tree_add_item(tree, hf_telnet_naws_subopt_height, tvb, offset, 2, ENC_BIG_ENDIAN);
639 /* BEGIN RFC-2217 (COM Port Control) Definitions */
641 #define TNCOMPORT_SIGNATURE 0
642 #define TNCOMPORT_SETBAUDRATE 1
643 #define TNCOMPORT_SETDATASIZE 2
644 #define TNCOMPORT_SETPARITY 3
645 #define TNCOMPORT_SETSTOPSIZE 4
646 #define TNCOMPORT_SETCONTROL 5
647 #define TNCOMPORT_NOTIFYLINESTATE 6
648 #define TNCOMPORT_NOTIFYMODEMSTATE 7
649 #define TNCOMPORT_FLOWCONTROLSUSPEND 8
650 #define TNCOMPORT_FLOWCONTROLRESUME 9
651 #define TNCOMPORT_SETLINESTATEMASK 10
652 #define TNCOMPORT_SETMODEMSTATEMASK 11
653 #define TNCOMPORT_PURGEDATA 12
655 /* END RFC-2217 (COM Port Control) Definitions */
657 static void
658 dissect_comport_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, int offset, int len,
659 proto_tree *tree, proto_item *item)
661 static const char *datasizes[] = {
662 "Request",
663 "<invalid>",
664 "<invalid>",
665 "<invalid>",
666 "<invalid>",
667 "5",
668 "6",
669 "7",
672 static const char *parities[] = {
673 "Request",
674 "None",
675 "Odd",
676 "Even",
677 "Mark",
678 "Space"
680 static const char *stops[] = {
681 "Request",
682 "1",
683 "2",
684 "1.5"
686 static const char *control[] = {
687 "Output Flow Control Request",
688 "Output Flow: None",
689 "Output Flow: XON/XOFF",
690 "Output Flow: CTS/RTS",
691 "Break Request",
692 "Break: ON",
693 "Break: OFF",
694 "DTR Request",
695 "DTR: ON",
696 "DTR: OFF",
697 "RTS Request",
698 "RTS: ON",
699 "RTS: OFF",
700 "Input Flow Control Request",
701 "Input Flow: None",
702 "Input Flow: XON/XOFF",
703 "Input Flow: CTS/RTS",
704 "Output Flow: DCD",
705 "Input Flow: DTR",
706 "Output Flow: DSR"
708 static const char *linestate_bits[] = {
709 "Data Ready",
710 "Overrun Error",
711 "Parity Error",
712 "Framing Error",
713 "Break Detected",
714 "Transfer Holding Register Empty",
715 "Transfer Shift Register Empty",
716 "Timeout Error"
718 static const char *modemstate_bits[] = {
719 "DCTS",
720 "DDSR",
721 "TERI",
722 "DDCD",
723 "CTS",
724 "DSR",
725 "RI",
726 "DCD"
728 static const char *purges[] = {
729 "Purge None",
730 "Purge RX",
731 "Purge TX",
732 "Purge RX/TX"
735 uint8_t cmd;
736 uint8_t isservercmd;
737 const char *source;
739 cmd = tvb_get_uint8(tvb, offset);
740 isservercmd = cmd > 99;
741 cmd = (isservercmd) ? (cmd - 100) : cmd;
742 source = (isservercmd) ? "Server" : "Client";
743 switch (cmd) {
744 case TNCOMPORT_SIGNATURE:
745 len--;
746 if (len == 0) {
747 proto_tree_add_string_format(tree, hf_telnet_comport_subopt_signature, tvb, offset, 1, "", "%s Requests Signature", source);
748 } else {
749 uint8_t *sig = tvb_get_string_enc(pinfo->pool, tvb, offset + 1, len, ENC_ASCII);
750 proto_tree_add_string_format(tree, hf_telnet_comport_subopt_signature, tvb, offset, 1 + len, sig,
751 "%s Signature: %s",source, sig);
753 break;
755 case TNCOMPORT_SETBAUDRATE:
756 len--;
757 if (len >= 4) {
758 uint32_t baud = tvb_get_ntohl(tvb, offset+1);
759 if (baud == 0) {
760 proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_baud_rate, tvb, offset, 5, 0, "%s Requests Baud Rate",source);
761 } else {
762 proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_baud_rate, tvb, offset, 5, baud, "%s Baud Rate: %d",source,baud);
764 } else {
765 expert_add_info_format(pinfo, item, &ei_telnet_invalid_baud_rate, "%s <Invalid Baud Rate Packet>", source);
767 break;
769 case TNCOMPORT_SETDATASIZE:
770 len--;
771 if (len >= 1) {
772 uint8_t datasize = tvb_get_uint8(tvb, offset+1);
773 const char *ds = (datasize > 8) ? "<invalid>" : datasizes[datasize];
774 proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_data_size, tvb, offset, 2, datasize,
775 "%s Data Size: %s",source,ds);
776 } else {
777 expert_add_info_format(pinfo, item, &ei_telnet_invalid_data_size, "%s <Invalid Data Size Packet>", source);
779 break;
781 case TNCOMPORT_SETPARITY:
782 len--;
783 if (len >= 1) {
784 uint8_t parity = tvb_get_uint8(tvb, offset+1);
785 const char *pr = (parity > 5) ? "<invalid>" : parities[parity];
786 proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_parity, tvb, offset, 2, parity,
787 "%s Parity: %s",source,pr);
788 } else {
789 expert_add_info_format(pinfo, item, &ei_telnet_invalid_parity, "%s <Invalid Parity Packet>", source);
791 break;
792 case TNCOMPORT_SETSTOPSIZE:
793 len--;
794 if (len >= 1) {
795 uint8_t stop = tvb_get_uint8(tvb, offset+1);
796 const char *st = (stop > 3) ? "<invalid>" : stops[stop];
797 proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_stop, tvb, offset, 2, stop,
798 "%s Stop: %s",source,st);
799 } else {
800 expert_add_info_format(pinfo, item, &ei_telnet_invalid_stop, "%s <Invalid Stop Packet>", source);
802 break;
804 case TNCOMPORT_SETCONTROL:
805 len--;
806 if (len >= 1) {
807 uint8_t crt = tvb_get_uint8(tvb, offset+1);
808 const char *c = (crt > 19) ? "Control: <invalid>" : control[crt];
809 proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_control, tvb, offset, 2, crt,
810 "%s Stop: %s",source,c);
811 } else {
812 expert_add_info_format(pinfo, item, &ei_telnet_invalid_control, "%s <Invalid Control Packet>", source);
814 break;
816 case TNCOMPORT_SETLINESTATEMASK:
817 case TNCOMPORT_NOTIFYLINESTATE:
818 len--;
819 if (len >= 1) {
820 const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
821 "%s Set Linestate Mask: %s" : "%s Linestate: %s";
822 int hf_line = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
823 hf_telnet_comport_set_linestate_mask : hf_telnet_comport_linestate;
824 char ls_buffer[512];
825 uint8_t ls = tvb_get_uint8(tvb, offset+1);
826 int print_count = 0;
827 int idx;
828 ls_buffer[0] = '\0';
829 for (idx = 0; idx < 8; idx++) {
830 int bit = ls & 1;
831 if (bit) {
832 if (print_count != 0) {
833 (void) g_strlcat(ls_buffer,", ",512);
835 (void) g_strlcat(ls_buffer,linestate_bits[idx], 512);
836 print_count++;
838 ls = ls >> 1;
840 proto_tree_add_string_format(tree, hf_line, tvb, offset, 2, ls_buffer, print_pattern, source, ls_buffer);
841 } else {
842 const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
843 "%s <Invalid Linestate Mask>" : "%s <Invalid Linestate Packet>";
844 expert_add_info_format(pinfo, item, &ei_telnet_invalid_linestate, print_pattern, source);
846 break;
848 case TNCOMPORT_SETMODEMSTATEMASK:
849 case TNCOMPORT_NOTIFYMODEMSTATE:
850 len--;
851 if (len >= 1) {
852 const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
853 "%s Set Modemstate Mask: %s" : "%s Modemstate: %s";
854 int hf_modem = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
855 hf_telnet_comport_set_modemstate_mask : hf_telnet_comport_modemstate;
856 char ms_buffer[256];
857 uint8_t ms = tvb_get_uint8(tvb, offset+1);
858 int print_count = 0;
859 int idx;
860 ms_buffer[0] = '\0';
861 for (idx = 0; idx < 8; idx++) {
862 int bit = ms & 1;
863 if (bit) {
864 if (print_count != 0) {
865 (void) g_strlcat(ms_buffer,", ",256);
867 (void) g_strlcat(ms_buffer,modemstate_bits[idx],256);
868 print_count++;
870 ms = ms >> 1;
872 proto_tree_add_string_format(tree, hf_modem, tvb, offset, 2, ms_buffer, print_pattern, source, ms_buffer);
873 } else {
874 const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
875 "%s <Invalid Modemstate Mask>" : "%s <Invalid Modemstate Packet>";
876 expert_add_info_format(pinfo, item, &ei_telnet_invalid_modemstate, print_pattern, source);
878 break;
880 case TNCOMPORT_FLOWCONTROLSUSPEND:
881 len--;
882 proto_tree_add_none_format(tree, hf_telnet_comport_subopt_flow_control_suspend, tvb, offset, 1, "%s Flow Control Suspend",source);
883 break;
885 case TNCOMPORT_FLOWCONTROLRESUME:
886 len--;
887 proto_tree_add_none_format(tree, hf_telnet_comport_subopt_flow_control_resume, tvb, offset, 1, "%s Flow Control Resume",source);
888 break;
890 case TNCOMPORT_PURGEDATA:
891 len--;
892 if (len >= 1) {
893 uint8_t purge = tvb_get_uint8(tvb, offset+1);
894 const char *p = (purge > 3) ? "<Purge invalid>" : purges[purge];
895 proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_purge, tvb, offset, 2, purge,
896 "%s %s",source,p);
897 } else {
898 expert_add_info_format(pinfo, item, &ei_telnet_invalid_purge, "%s <Invalid Purge Packet>", source);
900 break;
902 default:
903 expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
904 offset++;
905 len--;
906 if (len > 0)
907 proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
908 return;
913 static const value_string rfc_opt_vals[] = {
914 { 0, "OFF" },
915 { 1, "ON" },
916 { 2, "RESTART-ANY" },
917 { 3, "RESTART-XON" },
918 { 0, NULL }
921 static void
922 dissect_rfc_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
923 int len _U_, proto_tree *tree, proto_item *item _U_)
925 proto_tree_add_item(tree, hf_telnet_rfc_subopt_cmd, tvb, offset, 1, ENC_BIG_ENDIAN);
928 #define TN_ENC_IS 0
929 #define TN_ENC_SUPPORT 1
930 #define TN_ENC_REPLY 2
931 #define TN_ENC_START 3
932 #define TN_ENC_END 4
933 #define TN_ENC_REQUEST_START 5
934 #define TN_ENC_REQUEST_END 6
935 #define TN_ENC_ENC_KEYID 7
936 #define TN_ENC_DEC_KEYID 8
937 static const value_string enc_cmd_vals[] = {
938 { TN_ENC_IS, "IS" },
939 { TN_ENC_SUPPORT, "SUPPORT" },
940 { TN_ENC_REPLY, "REPLY" },
941 { TN_ENC_START, "START" },
942 { TN_ENC_END, "END" },
943 { TN_ENC_REQUEST_START, "REQUEST-START" },
944 { TN_ENC_REQUEST_END, "REQUEST-END" },
945 { TN_ENC_ENC_KEYID, "ENC_KEYID" },
946 { TN_ENC_DEC_KEYID, "DEC_KEYID" },
947 { 0, NULL }
950 #define TN_ENCTYPE_NULL 0
951 #define TN_ENCTYPE_DES_CFB64 1
952 #define TN_ENCTYPE_DES_OFB64 2
953 #define TN_ENCTYPE_DES3_CFB64 3
954 #define TN_ENCTYPE_DES3_OFB64 4
955 #define TN_ENCTYPE_CAST5_40_CFB64 8
956 #define TN_ENCTYPE_CAST5_40_OFB64 9
957 #define TN_ENCTYPE_CAST128_CFB64 10
958 #define TN_ENCTYPE_CAST128_OFB64 11
959 static const value_string enc_type_vals[] = {
960 { TN_ENCTYPE_NULL, "NULL" },
961 { TN_ENCTYPE_DES_CFB64, "DES_CFB64" },
962 { TN_ENCTYPE_DES_OFB64, "DES_OFB64" },
963 { TN_ENCTYPE_DES3_CFB64, "DES3_CFB64" },
964 { TN_ENCTYPE_DES3_OFB64, "DES3_OFB64" },
965 { TN_ENCTYPE_CAST5_40_CFB64, "CAST5_40_CFB64" },
966 { TN_ENCTYPE_CAST5_40_OFB64, "CAST5_40_OFB64" },
967 { TN_ENCTYPE_CAST128_CFB64, "CAST128_CFB64" },
968 { TN_ENCTYPE_CAST128_OFB64, "CAST128_OFB64" },
969 { 0, NULL }
973 #define TN_AC_IS 0
974 #define TN_AC_SEND 1
975 #define TN_AC_REPLY 2
976 #define TN_AC_NAME 3
977 static const value_string auth_cmd_vals[] = {
978 { TN_AC_IS, "IS" },
979 { TN_AC_SEND, "SEND" },
980 { TN_AC_REPLY, "REPLY" },
981 { TN_AC_NAME, "NAME" },
982 { 0, NULL }
985 #define TN_AT_NULL 0
986 #define TN_AT_KRB4 1
987 #define TN_AT_KRB5 2
988 #define TN_AT_SPX 3
989 #define TN_AT_MINK 4
990 #define TN_AT_SRP 5
991 #define TN_AT_RSA 6
992 #define TN_AT_SSL 7
993 #define TN_AT_LOKI 10
994 #define TN_AT_SSA 11
995 #define TN_AT_KEA_SJ 12
996 #define TN_AT_KEA_SJ_INTEG 13
997 #define TN_AT_DSS 14
998 #define TN_AT_NTLM 15
999 static const value_string auth_type_vals[] = {
1000 { TN_AT_NULL, "NULL" },
1001 { TN_AT_KRB4, "Kerberos v4" },
1002 { TN_AT_KRB5, "Kerberos v5" },
1003 { TN_AT_SPX, "SPX" },
1004 { TN_AT_MINK, "MINK" },
1005 { TN_AT_SRP, "SRP" },
1006 { TN_AT_RSA, "RSA" },
1007 { TN_AT_SSL, "SSL" },
1008 { TN_AT_LOKI, "LOKI" },
1009 { TN_AT_SSA, "SSA" },
1010 { TN_AT_KEA_SJ, "KEA_SJ" },
1011 { TN_AT_KEA_SJ_INTEG, "KEA_SJ_INTEG" },
1012 { TN_AT_DSS, "DSS" },
1013 { TN_AT_NTLM, "NTLM" },
1014 { 0, NULL }
1016 static const true_false_string auth_mod_cred_fwd = {
1017 "Client WILL forward auth creds",
1018 "Client will NOT forward auth creds"
1020 static const true_false_string auth_mod_how = {
1021 "Mutual authentication",
1022 "One Way authentication"
1024 #define TN_AM_OFF 0x00
1025 #define TN_AM_USING_TELOPT 0x01
1026 #define TN_AM_AFTER_EXCHANGE 0x02
1027 #define TN_AM_RESERVED 0x04
1028 static const value_string auth_mod_enc[] = {
1029 { TN_AM_OFF, "Off" },
1030 { TN_AM_USING_TELOPT, "Telnet Options" },
1031 { TN_AM_AFTER_EXCHANGE, "After Exchange" },
1032 { TN_AM_RESERVED, "Reserved" },
1033 { 0, NULL }
1035 #define TN_KRB5_TYPE_AUTH 0
1036 #define TN_KRB5_TYPE_REJECT 1
1037 #define TN_KRB5_TYPE_ACCEPT 2
1038 #define TN_KRB5_TYPE_RESPONSE 3
1039 #define TN_KRB5_TYPE_FORWARD 4
1040 #define TN_KRB5_TYPE_FORWARD_ACCEPT 5
1041 #define TN_KRB5_TYPE_FORWARD_REJECT 6
1042 static const value_string auth_krb5_types[] = {
1043 { TN_KRB5_TYPE_AUTH, "Auth" },
1044 { TN_KRB5_TYPE_REJECT, "Reject" },
1045 { TN_KRB5_TYPE_ACCEPT, "Accept" },
1046 { TN_KRB5_TYPE_RESPONSE, "Response" },
1047 { TN_KRB5_TYPE_FORWARD, "Forward" },
1048 { TN_KRB5_TYPE_FORWARD_ACCEPT, "Forward Accept" },
1049 { TN_KRB5_TYPE_FORWARD_REJECT, "Forward Reject" },
1050 { 0, NULL }
1052 static void
1053 dissect_authentication_type_pair(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, proto_tree *tree)
1055 static int * const auth_mods[] = {
1056 &hf_telnet_auth_mod_enc,
1057 &hf_telnet_auth_mod_cred_fwd,
1058 &hf_telnet_auth_mod_how,
1059 &hf_telnet_auth_mod_who,
1060 NULL
1063 proto_tree_add_item(tree, hf_telnet_auth_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1064 proto_tree_add_bitmask_list(tree, tvb, offset+1, 1, auth_mods, ENC_BIG_ENDIAN);
1067 /* Assume no telnet option subnegotiation exceeds 10 kB (arbitrary limit). */
1068 #define MAX_TELNET_OPTION_SUBNEG_LEN 10240
1070 static tvbuff_t *
1071 unescape_and_tvbuffify_telnet_option(packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
1073 tvbuff_t *option_subneg_tvb;
1074 uint8_t *buf;
1075 const uint8_t *spos;
1076 uint8_t *dpos;
1077 int skip, l;
1079 if(len >= MAX_TELNET_OPTION_SUBNEG_LEN)
1080 return NULL;
1082 spos = tvb_get_ptr(tvb, offset, len);
1083 const uint8_t *last_src_pos = spos + len - 1;
1084 buf = (uint8_t *)wmem_alloc(pinfo->pool, len);
1085 dpos = buf;
1086 skip = 0;
1087 l = len;
1088 while(l > 0) {
1089 // XXX Add expert info if spos >= last_src_pos?
1090 if(spos < last_src_pos && (spos[0] == 0xff) && (spos[1] == 0xff)) {
1091 skip++;
1092 l -= 2;
1093 *(dpos++) = 0xff;
1094 spos += 2;
1095 continue;
1097 *(dpos++) = *(spos++);
1098 l--;
1100 option_subneg_tvb = tvb_new_child_real_data(tvb, buf, len-skip, len-skip);
1101 add_new_data_source(pinfo, option_subneg_tvb, "Unpacked Telnet Option");
1103 return option_subneg_tvb;
1107 /* as per RFC2942 */
1108 static void
1109 dissect_krb5_authentication_data(packet_info *pinfo, tvbuff_t *tvb, int offset, int len, proto_tree *tree, uint8_t acmd)
1111 tvbuff_t *krb5_tvb;
1112 uint8_t krb5_cmd;
1114 krb5_cmd=tvb_get_uint8(tvb, offset);
1115 proto_tree_add_uint(tree, hf_telnet_auth_krb5_type, tvb, offset, 1, krb5_cmd);
1116 offset++;
1117 len--;
1120 /* IAC SB AUTHENTICATION IS <authentication-type-pair> AUTH <Kerberos V5 KRB_AP_REQ message> IAC SE */
1121 if((acmd==TN_AC_IS)&&(krb5_cmd==TN_KRB5_TYPE_AUTH)){
1122 if(len){
1123 krb5_tvb=tvb_new_subset_length(tvb, offset, len);
1124 dissect_kerberos_main(krb5_tvb, pinfo, tree, false, NULL);
1130 /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> ACCEPT IAC SE */
1131 /* nothing more to dissect */
1135 /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> REJECT <optional reason for rejection> IAC SE*/
1136 /*qqq*/
1139 /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> RESPONSE <KRB_AP_REP message> IAC SE */
1140 if((acmd==TN_AC_REPLY)&&(krb5_cmd==TN_KRB5_TYPE_RESPONSE)){
1141 if(len){
1142 krb5_tvb=tvb_new_subset_length(tvb, offset, len);
1143 dissect_kerberos_main(krb5_tvb, pinfo, tree, false, NULL);
1148 /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD <KRB_CRED message> IAC SE */
1149 /* XXX unclear what this one looks like */
1152 /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_ACCEPT IAC SE */
1153 /* nothing more to dissect */
1157 /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_REJECT */
1158 /* nothing more to dissect */
1162 #define TN_AUTH_SSL_START 1
1163 #define TN_AUTH_SSL_ACCEPT 2
1164 #define TN_AUTH_SSL_REJECT 3
1166 static const value_string ssl_auth_status[] = {
1167 { TN_AUTH_SSL_START, "Start" },
1168 { TN_AUTH_SSL_ACCEPT, "Accepted" },
1169 { TN_AUTH_SSL_REJECT, "Rejected" },
1170 { 0, NULL }
1173 static void
1174 dissect_ssl_authentication_data(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *tree, uint8_t acmd)
1176 unsigned ssl_status;
1178 proto_tree_add_item_ret_uint(tree, hf_telnet_auth_ssl_status, tvb, offset, 1, ENC_NA, &ssl_status);
1180 if (acmd == TN_AC_REPLY && ssl_status == TN_AUTH_SSL_ACCEPT)
1181 /* TLS negotiation will immediately follow this packet. */
1182 ssl_starttls_ack(tls_handle, pinfo, telnet_handle);
1185 /* as per RFC2941 */
1186 static void
1187 dissect_authentication_data(packet_info *pinfo, tvbuff_t *tvb, int offset, int len, proto_tree *tree, uint8_t acmd)
1189 uint8_t auth_type;
1191 dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1192 auth_type = tvb_get_uint8(tvb, offset);
1193 offset += 2;
1194 len -= 2;
1196 switch (auth_type) {
1197 case TN_AT_NULL:
1198 break;
1200 case TN_AT_SSL:
1201 dissect_ssl_authentication_data(pinfo, tvb, offset, tree, acmd);
1202 break;
1204 case TN_AT_KRB5:
1205 dissect_krb5_authentication_data(pinfo, tvb, offset, len, tree, acmd);
1206 break;
1208 default:
1209 /* We don't (yet) know how to dissect the data for this authentication type. */
1210 if (len > 0)
1211 proto_tree_add_bytes_format(tree, hf_telnet_auth_data, tvb, offset, len, NULL, "Unhandled authentication data");
1215 static void
1216 dissect_authentication_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, int offset, int len,
1217 proto_tree *tree, proto_item *item _U_)
1219 uint8_t acmd;
1221 acmd=tvb_get_uint8(tvb, offset);
1222 proto_tree_add_uint(tree, hf_telnet_auth_cmd, tvb, offset, 1, acmd);
1223 offset++;
1224 len--;
1226 switch(acmd){
1227 case TN_AC_REPLY:
1228 case TN_AC_IS:
1229 dissect_authentication_data(pinfo, tvb, offset, len, tree, acmd);
1230 break;
1232 case TN_AC_SEND:
1233 while(len>0){
1234 dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1235 offset+=2;
1236 len-=2;
1238 break;
1240 case TN_AC_NAME:
1241 proto_tree_add_item(tree, hf_telnet_auth_name, tvb, offset, len, ENC_ASCII);
1242 break;
1246 /* This function only uses the octet in the buffer at 'offset' */
1247 static void dissect_encryption_type(tvbuff_t *tvb, int offset, proto_tree *tree) {
1248 uint8_t etype;
1249 etype = tvb_get_uint8(tvb, offset);
1250 proto_tree_add_uint(tree, hf_telnet_enc_type, tvb, offset, 1, etype);
1253 static void
1254 dissect_encryption_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, int offset, int len,
1255 proto_tree *tree, proto_item *item)
1257 uint8_t ecmd, key_first_octet;
1259 ecmd = tvb_get_uint8(tvb, offset);
1260 proto_tree_add_uint(tree, hf_telnet_enc_cmd, tvb, offset, 1, ecmd);
1262 offset++;
1263 len--;
1265 switch(ecmd) {
1266 case TN_ENC_IS:
1267 case TN_ENC_REPLY:
1268 /* encryption type, type-specific data ... */
1269 if (len > 0) {
1270 dissect_encryption_type(tvb, offset, tree);
1271 offset++;
1272 len--;
1273 proto_tree_add_item(tree, hf_telnet_enc_type_data, tvb, offset, len, ENC_NA);
1275 break;
1277 case TN_ENC_SUPPORT:
1278 /* list of encryption types ... */
1279 while (len > 0) {
1280 dissect_encryption_type(tvb, offset, tree);
1281 offset++;
1282 len--;
1284 break;
1286 case TN_ENC_START:
1287 /* keyid ... */
1288 if (len > 0) {
1289 key_first_octet = tvb_get_uint8(tvb, offset);
1290 proto_tree_add_bytes_format(tree, hf_telnet_enc_key_id, tvb, offset, len, NULL, (key_first_octet == 0) ? "Default key" : "Key ID");
1292 break;
1294 case TN_ENC_END:
1295 /* no data */
1296 break;
1298 case TN_ENC_REQUEST_START:
1299 /* (optional) keyid */
1300 if (len > 0)
1301 proto_tree_add_bytes_format(tree, hf_telnet_enc_key_id, tvb, offset, len, NULL, "Key ID (advisory)");
1302 break;
1304 case TN_ENC_REQUEST_END:
1305 /* no data */
1306 break;
1308 case TN_ENC_ENC_KEYID:
1309 case TN_ENC_DEC_KEYID:
1310 /* (optional) keyid - if not supplied, there are no more known keys */
1311 if (len > 0)
1312 proto_tree_add_item(tree, hf_telnet_enc_key_id, tvb, offset, len, ENC_NA);
1313 break;
1315 default:
1316 expert_add_info(pinfo, item, &ei_telnet_enc_cmd_unknown);
1320 #define VMWARE_TELNET_EXT 232
1322 /* Option Subnegotiation */
1323 #define VMWARE_KNOWN_SUBOPTIONS_1 0
1324 #define VMWARE_KNOWN_SUBOPTIONS_2 1
1326 /* Unknown Command Response */
1327 #define VMWARE_UNKNOWN_SUBOPTION_RCVD_1 2
1328 #define VMWARE_UNKNOWN_SUBOPTION_RCVD_2 3
1330 /* vMotion Notification */
1331 #define VMWARE_VMOTION_BEGIN 40
1332 #define VMWARE_VMOTION_GOAHEAD 41
1333 #define VMWARE_VMOTION_NOTNOW 43
1334 #define VMWARE_VMOTION_PEER 44
1335 #define VMWARE_VMOTION_PEER_OK 45
1336 #define VMWARE_VMOTION_COMPLETE 46
1337 #define VMWARE_VMOTION_ABORT 48
1339 /* Proxy operation */
1340 #define VMWARE_DO_PROXY 70
1341 #define VMWARE_WILL_PROXY 71
1342 #define VMWARE_WONT_PROXY 73
1344 /* Virtual machine identification */
1345 #define VMWARE_VM_VC_UUID 80
1346 #define VMWARE_GET_VM_VC_UUID 81
1347 #define VMWARE_VM_NAME 82
1348 #define VMWARE_GET_VM_NAME 83
1349 #define VMWARE_VM_BIOS_UUID 84
1350 #define VMWARE_GET_VM_BIOS_UUID 85
1351 #define VMWARE_VM_LOCATION_UUID 86
1352 #define VMWARE_GET_VM_LOCATION_UUID 87
1354 static const value_string vmware_cmd_vals[] = {
1355 { VMWARE_KNOWN_SUBOPTIONS_1, "KNOWN-SUBOPTIONS-1" },
1356 { VMWARE_KNOWN_SUBOPTIONS_2, "KNOWN-SUBOPTIONS-2" },
1357 { VMWARE_UNKNOWN_SUBOPTION_RCVD_1, "UNKNOWN-SUBOPTION-RCVD-1" },
1358 { VMWARE_UNKNOWN_SUBOPTION_RCVD_2, "UNKNOWN-SUBOPTION-RCVD-2" },
1359 { VMWARE_VMOTION_BEGIN, "VMOTION-BEGIN" },
1360 { VMWARE_VMOTION_GOAHEAD, "VMOTION-GOAHEAD" },
1361 { VMWARE_VMOTION_NOTNOW, "VMOTION-NOTNOW" },
1362 { VMWARE_VMOTION_PEER, "VMOTION-PEER" },
1363 { VMWARE_VMOTION_PEER_OK, "VMOTION-PEER-OK" },
1364 { VMWARE_VMOTION_COMPLETE, "VMOTION-COMPLETE" },
1365 { VMWARE_VMOTION_ABORT, "VMOTION-ABORT" },
1366 { VMWARE_DO_PROXY, "DO-PROXY" },
1367 { VMWARE_WILL_PROXY, "WILL-PROXY" },
1368 { VMWARE_WONT_PROXY, "WONT-PROXY" },
1369 { VMWARE_VM_VC_UUID, "VM-VC-UUID" },
1370 { VMWARE_GET_VM_VC_UUID, "GET-VM-VC-UUID" },
1371 { VMWARE_VM_NAME, "VM-NAME" },
1372 { VMWARE_GET_VM_NAME, "GET-VM-NAME" },
1373 { VMWARE_VM_BIOS_UUID, "VM-BIOS-UUID" },
1374 { VMWARE_GET_VM_BIOS_UUID, "GET-VM-BIOS-UUID" },
1375 { VMWARE_VM_LOCATION_UUID, "VM-LOCATION-UUID" },
1376 { VMWARE_GET_VM_LOCATION_UUID, "GET-VM-LOCATION-UUID" },
1377 { 0, NULL }
1380 /* Encoding for the "direction" argument to DO-PROXY: */
1381 #define VMWARE_PROXY_DIRECTION_CLIENT 'C'
1382 #define VMWARE_PROXY_DIRECTION_SERVER 'S'
1384 static const value_string vmware_proxy_direction_vals[] = {
1385 { VMWARE_PROXY_DIRECTION_CLIENT, "Client" },
1386 { VMWARE_PROXY_DIRECTION_SERVER, "Server" },
1387 { 0, NULL }
1390 static void
1391 dissect_vmware_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset, int len,
1392 proto_tree *tree, proto_item *item _U_)
1395 * The VMware virtual serial port proxy uses the Telnet protocol over TCP
1396 * port 13370. Use "Decode As..." or specify "-d tcp.port==13370,telnet" on
1397 * the command-line.
1400 uint8_t vmwcmd;
1402 vmwcmd = tvb_get_uint8(tvb, offset);
1403 proto_tree_add_uint(tree, hf_telnet_vmware_cmd, tvb, offset, 1, vmwcmd);
1404 offset++;
1405 len--;
1407 switch (vmwcmd) {
1409 /* --- Option Subnegotiation --- */
1411 case VMWARE_KNOWN_SUBOPTIONS_1:
1412 case VMWARE_KNOWN_SUBOPTIONS_2:
1413 /* Data: suboptions... */
1414 while (len > 0) {
1415 proto_tree_add_item(tree, hf_telnet_vmware_known_suboption_code, tvb, offset, 1, ENC_NA);
1416 offset++;
1417 len--;
1419 break;
1421 /* --- Unknown Command Response --- */
1423 case VMWARE_UNKNOWN_SUBOPTION_RCVD_1:
1424 case VMWARE_UNKNOWN_SUBOPTION_RCVD_2:
1425 /* Data: suboption */
1426 proto_tree_add_item(tree, hf_telnet_vmware_unknown_subopt_code, tvb, offset, 1, ENC_NA);
1427 offset++;
1428 len--;
1429 break;
1431 /* --- vMotion Notification --- */
1433 case VMWARE_VMOTION_BEGIN:
1434 case VMWARE_VMOTION_NOTNOW:
1435 case VMWARE_VMOTION_PEER_OK:
1436 case VMWARE_VMOTION_COMPLETE: {
1437 /* Data: sequence */
1438 telnet_conv_info_t *session = telnet_get_session(pinfo);
1439 if (session->vmotion_sequence_len < 0) {
1441 * There is nothing which _requires_ that the sequence length be constant
1442 * throughout a Telnet conversation, but all implementations currently
1443 * behave that way and here we assume it will be so. If that changes,
1444 * subsequent VMOTION-GOAHEAD/VMOTION-PEER messages might be incorrectly
1445 * dissected, with bytes incorrectly assigned to the sequence or secret
1446 * fields. This should not be a big deal.
1448 session->vmotion_sequence_len = len;
1450 proto_tree_add_item(tree, hf_telnet_vmware_vmotion_sequence, tvb, offset, len, ENC_NA);
1451 offset += len;
1452 len = 0;
1454 break;
1456 case VMWARE_VMOTION_GOAHEAD:
1457 case VMWARE_VMOTION_PEER: {
1458 /* Data: sequence secret */
1459 telnet_conv_info_t *session = telnet_get_session(pinfo);
1462 * The lack of delimiter between "sequence" and "secret" makes dissection
1463 * challenging. We need to track the "vMotion conversation", which spans
1464 * two Telnet conversations with different endpoints. The vMotion
1465 * conversation is identified by a blob containing the concatenation of the
1466 * sequence and secret.
1468 if ((vmwcmd == VMWARE_VMOTION_GOAHEAD && session->vmotion_sequence_len >= 0) ||
1469 (vmwcmd == VMWARE_VMOTION_PEER && session->vmotion_sequence_len < 0)) {
1470 conversation_element_t conv_key[2] = {
1472 .type = CE_BLOB,
1473 .blob = {
1474 .val = tvb_memdup(pinfo->pool, tvb, offset, len),
1475 .len = len,
1479 .type = CE_CONVERSATION_TYPE,
1480 .conversation_type_val = CONVERSATION_VSPC_VMOTION,
1483 conversation_t *vmotion_conv = find_conversation_full(pinfo->num, conv_key);
1485 if (vmwcmd == VMWARE_VMOTION_GOAHEAD && vmotion_conv == NULL) {
1487 * We have the full sequence and secret and we know the length of the
1488 * "sequence" field. Stash it (or, really, its session) where we can
1489 * find it later.
1491 vmotion_conv = conversation_new_full(pinfo->num, conv_key);
1492 conversation_add_proto_data(vmotion_conv, proto_telnet, session);
1493 } else if (vmwcmd == VMWARE_VMOTION_PEER && vmotion_conv != NULL) {
1495 * Try to find the length of the "sequence" field from the conversation
1496 * containing the VMOTION-GOAHEAD message.
1498 telnet_conv_info_t const *source_session =
1499 (telnet_conv_info_t const *)conversation_get_proto_data(vmotion_conv, proto_telnet);
1501 if (source_session != NULL) {
1502 session->vmotion_sequence_len = source_session->vmotion_sequence_len;
1504 /* The secret is only used once, so the vMotion conversation ends here. */
1505 vmotion_conv->last_frame = pinfo->num;
1507 wmem_free(pinfo->pool, (void *)conv_key[0].blob.val);
1509 if (session->vmotion_sequence_len >= 0 && session->vmotion_sequence_len <= len) {
1510 proto_tree_add_item(tree, hf_telnet_vmware_vmotion_sequence, tvb, offset, (int)session->vmotion_sequence_len, ENC_NA);
1511 offset += (int)session->vmotion_sequence_len;
1512 len -= (int)session->vmotion_sequence_len;
1514 proto_tree_add_item(tree, hf_telnet_vmware_vmotion_secret, tvb, offset, len, ENC_NA);
1515 offset += len;
1516 len = 0;
1517 } else {
1519 * With no delimiter between "sequence" and "secret", nor any other way
1520 * of determining the lengths of those fields, we lack the information to
1521 * be able to dissect this. Skip it.
1523 offset += len;
1524 len = 0;
1527 break;
1529 case VMWARE_VMOTION_ABORT:
1530 /* no data */
1531 break;
1533 /* --- Proxy Operation --- */
1535 case VMWARE_DO_PROXY:
1536 /* Data: direction serviceUri */
1537 proto_tree_add_item(tree, hf_telnet_vmware_proxy_direction, tvb, offset, 1, ENC_NA);
1538 offset++;
1539 len--;
1540 proto_tree_add_item(tree, hf_telnet_vmware_proxy_serviceUri, tvb, offset, len, ENC_UTF_8);
1541 offset += len;
1542 len = 0;
1543 break;
1545 case VMWARE_WILL_PROXY:
1546 case VMWARE_WONT_PROXY:
1547 /* no data */
1548 break;
1550 /* --- Virtual Machine Identification --- */
1552 case VMWARE_GET_VM_VC_UUID:
1553 case VMWARE_GET_VM_NAME:
1554 case VMWARE_GET_VM_BIOS_UUID:
1555 case VMWARE_GET_VM_LOCATION_UUID:
1556 /* no data */
1557 break;
1559 case VMWARE_VM_NAME:
1560 /* Data: vm-name */
1561 proto_tree_add_item(tree, hf_telnet_vmware_vm_name, tvb, offset, len, ENC_UTF_8);
1562 offset += len;
1563 len = 0;
1564 break;
1566 case VMWARE_VM_VC_UUID:
1567 /* Data: vm-uuid */
1568 proto_tree_add_item(tree, hf_telnet_vmware_vm_vc_uuid, tvb, offset, len, ENC_ASCII);
1569 offset += len;
1570 len = 0;
1571 break;
1573 case VMWARE_VM_BIOS_UUID:
1574 /* Data: vm-uuid */
1575 proto_tree_add_item(tree, hf_telnet_vmware_vm_bios_uuid, tvb, offset, len, ENC_ASCII);
1576 offset += len;
1577 len = 0;
1578 break;
1580 case VMWARE_VM_LOCATION_UUID:
1581 /* Data: vm-uuid */
1582 proto_tree_add_item(tree, hf_telnet_vmware_vm_location_uuid, tvb, offset, len, ENC_ASCII);
1583 offset += len;
1584 len = 0;
1585 break;
1587 default:
1588 expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, vmwcmd);
1589 if (len > 0)
1590 proto_tree_add_item(tree, hf_telnet_subcommand_data, tvb, offset, len, ENC_NA);
1591 return;
1593 if (len > 0) {
1594 proto_item *pi = proto_tree_add_bytes_format(tree, hf_telnet_subcommand_data, tvb, offset, len, NULL, "Unexpected data");
1595 expert_add_info_format(pinfo, pi, &ei_telnet_vmware_unexp_data, "%u bytes unexpected data", len);
1599 static const tn_opt options[] = {
1601 "Binary Transmission", /* RFC 856 */
1602 NULL, /* no suboption negotiation */
1603 NO_LENGTH,
1605 NULL
1608 "Echo", /* RFC 857 */
1609 NULL, /* no suboption negotiation */
1610 NO_LENGTH,
1612 NULL
1615 "Reconnection", /* DOD Protocol Handbook */
1616 NULL,
1617 NO_LENGTH,
1619 NULL
1622 "Suppress Go Ahead", /* RFC 858 */
1623 NULL, /* no suboption negotiation */
1624 NO_LENGTH,
1626 NULL
1629 "Approx Message Size Negotiation", /* Ethernet spec(!) */
1630 NULL,
1631 NO_LENGTH,
1633 NULL
1636 "Status", /* RFC 859 */
1637 &ett_status_subopt,
1638 VARIABLE_LENGTH,
1640 NULL /* XXX - fill me in */
1643 "Timing Mark", /* RFC 860 */
1644 NULL, /* no suboption negotiation */
1645 NO_LENGTH,
1647 NULL
1650 "Remote Controlled Trans and Echo", /* RFC 726 */
1651 &ett_rcte_subopt,
1652 VARIABLE_LENGTH,
1654 NULL /* XXX - fill me in */
1657 "Output Line Width", /* DOD Protocol Handbook */
1658 &ett_olw_subopt,
1659 VARIABLE_LENGTH, /* XXX - fill me in */
1660 0, /* XXX - fill me in */
1661 NULL /* XXX - fill me in */
1664 "Output Page Size", /* DOD Protocol Handbook */
1665 &ett_ops_subopt,
1666 VARIABLE_LENGTH, /* XXX - fill me in */
1667 0, /* XXX - fill me in */
1668 NULL /* XXX - fill me in */
1671 "Output Carriage-Return Disposition", /* RFC 652 */
1672 &ett_crdisp_subopt,
1673 FIXED_LENGTH,
1675 NULL /* XXX - fill me in */
1678 "Output Horizontal Tab Stops", /* RFC 653 */
1679 &ett_htstops_subopt,
1680 VARIABLE_LENGTH,
1682 dissect_htstops_subopt
1685 "Output Horizontal Tab Disposition", /* RFC 654 */
1686 &ett_htdisp_subopt,
1687 FIXED_LENGTH,
1689 NULL /* XXX - fill me in */
1692 "Output Formfeed Disposition", /* RFC 655 */
1693 &ett_ffdisp_subopt,
1694 FIXED_LENGTH,
1696 NULL /* XXX - fill me in */
1699 "Output Vertical Tabstops", /* RFC 656 */
1700 &ett_vtstops_subopt,
1701 VARIABLE_LENGTH,
1703 NULL /* XXX - fill me in */
1706 "Output Vertical Tab Disposition", /* RFC 657 */
1707 &ett_vtdisp_subopt,
1708 FIXED_LENGTH,
1710 NULL /* XXX - fill me in */
1713 "Output Linefeed Disposition", /* RFC 658 */
1714 &ett_lfdisp_subopt,
1715 FIXED_LENGTH,
1717 NULL /* XXX - fill me in */
1720 "Extended ASCII", /* RFC 698 */
1721 &ett_extasc_subopt,
1722 FIXED_LENGTH,
1724 NULL /* XXX - fill me in */
1727 "Logout", /* RFC 727 */
1728 NULL, /* no suboption negotiation */
1729 NO_LENGTH,
1731 NULL
1734 "Byte Macro", /* RFC 735 */
1735 &ett_bytemacro_subopt,
1736 VARIABLE_LENGTH,
1738 NULL /* XXX - fill me in */
1741 "Data Entry Terminal", /* RFC 732, RFC 1043 */
1742 &ett_det_subopt,
1743 VARIABLE_LENGTH,
1745 NULL /* XXX - fill me in */
1748 "SUPDUP", /* RFC 734, RFC 736 */
1749 NULL, /* no suboption negotiation */
1750 NO_LENGTH,
1752 NULL
1755 "SUPDUP Output", /* RFC 749 */
1756 &ett_supdupout_subopt,
1757 VARIABLE_LENGTH,
1759 NULL /* XXX - fill me in */
1762 "Send Location", /* RFC 779 */
1763 &ett_sendloc_subopt,
1764 VARIABLE_LENGTH,
1766 NULL /* XXX - fill me in */
1769 "Terminal Type", /* RFC 1091 */
1770 &ett_termtype_subopt,
1771 VARIABLE_LENGTH,
1773 dissect_string_subopt
1776 "End of Record", /* RFC 885 */
1777 NULL, /* no suboption negotiation */
1778 NO_LENGTH,
1780 NULL
1783 "TACACS User Identification", /* RFC 927 */
1784 &ett_tacacsui_subopt,
1785 FIXED_LENGTH,
1787 NULL /* XXX - fill me in */
1790 "Output Marking", /* RFC 933 */
1791 &ett_outmark_subopt,
1792 VARIABLE_LENGTH,
1794 dissect_outmark_subopt,
1797 "Terminal Location Number", /* RFC 946 */
1798 &ett_tlocnum_subopt,
1799 VARIABLE_LENGTH,
1801 NULL /* XXX - fill me in */
1804 "Telnet 3270 Regime", /* RFC 1041 */
1805 &ett_tn3270reg_subopt,
1806 VARIABLE_LENGTH,
1808 dissect_tn3270_regime_subopt
1811 "X.3 PAD", /* RFC 1053 */
1812 &ett_x3pad_subopt,
1813 VARIABLE_LENGTH,
1815 NULL /* XXX - fill me in */
1818 "Negotiate About Window Size", /* RFC 1073, DW183 */
1819 &ett_naws_subopt,
1820 FIXED_LENGTH,
1822 dissect_naws_subopt
1825 "Terminal Speed", /* RFC 1079 */
1826 &ett_tspeed_subopt,
1827 VARIABLE_LENGTH,
1829 NULL /* XXX - fill me in */
1832 "Remote Flow Control", /* RFC 1372 */
1833 &ett_rfc_subopt,
1834 FIXED_LENGTH,
1836 dissect_rfc_subopt
1839 "Linemode", /* RFC 1184 */
1840 &ett_linemode_subopt,
1841 VARIABLE_LENGTH,
1843 NULL /* XXX - fill me in */
1846 "X Display Location", /* RFC 1096 */
1847 &ett_xdpyloc_subopt,
1848 VARIABLE_LENGTH,
1850 dissect_string_subopt
1853 "Environment Option", /* RFC 1408, RFC 1571 */
1854 &ett_env_subopt,
1855 VARIABLE_LENGTH,
1857 NULL /* XXX - fill me in */
1860 "Authentication Option", /* RFC 2941 */
1861 &ett_auth_subopt,
1862 VARIABLE_LENGTH,
1864 dissect_authentication_subopt
1867 "Encryption Option", /* RFC 2946 */
1868 &ett_enc_subopt,
1869 VARIABLE_LENGTH,
1871 dissect_encryption_subopt
1874 "New Environment Option", /* RFC 1572 */
1875 &ett_newenv_subopt,
1876 VARIABLE_LENGTH,
1878 NULL /* XXX - fill me in */
1881 "TN3270E", /* RFC 1647 */
1882 &ett_tn3270e_subopt,
1883 VARIABLE_LENGTH,
1885 dissect_tn3270e_subopt
1888 "XAUTH", /* XAUTH */
1889 &ett_xauth_subopt,
1890 VARIABLE_LENGTH,
1892 NULL /* XXX - fill me in */
1895 "CHARSET", /* CHARSET */
1896 &ett_charset_subopt,
1897 VARIABLE_LENGTH,
1899 NULL /* XXX - fill me in */
1902 "Remote Serial Port", /* Remote Serial Port */
1903 &ett_rsp_subopt,
1904 VARIABLE_LENGTH,
1906 NULL /* XXX - fill me in */
1909 "COM Port Control", /* RFC 2217 */
1910 &ett_comport_subopt,
1911 VARIABLE_LENGTH,
1913 dissect_comport_subopt
1916 "Suppress Local Echo", /* draft-rfced-exp-atmar-00 */
1917 NULL,
1918 NO_LENGTH,
1920 NULL
1923 "Start TLS", /* draft-ietf-tn3270e-telnet-tls-06 */
1924 &ett_starttls_subopt,
1925 FIXED_LENGTH,
1927 dissect_starttls_subopt
1930 "KERMIT", /* RFC 2840 */
1931 NULL,
1932 VARIABLE_LENGTH,
1934 NULL /* XXX - stub */
1937 "SEND-URL", /* draft-croft-telnet-url-trans-00 */
1938 NULL,
1939 VARIABLE_LENGTH,
1941 NULL /* XXX - stub */
1944 "FORWARD_X", /* draft-altman-telnet-fwdx-03 */
1945 NULL,
1946 VARIABLE_LENGTH,
1948 NULL /* XXX - stub */
1953 static const tn_opt telnet_opt_vmware = {
1954 "VMware Virtual Serial Port Proxy",
1955 NULL,
1956 VARIABLE_LENGTH,
1958 dissect_vmware_subopt
1961 static const tn_opt telnet_opt_unknown = {
1962 "<unknown option>",
1963 NULL,
1964 VARIABLE_LENGTH,
1966 NULL
1969 static const tn_opt *
1970 telnet_find_option(uint8_t opt_byte)
1972 if (opt_byte < array_length(options))
1973 return &options[opt_byte];
1975 if (opt_byte == VMWARE_TELNET_EXT)
1976 return &telnet_opt_vmware;
1978 return &telnet_opt_unknown;
1981 static int
1982 telnet_sub_option(packet_info *pinfo, proto_tree *option_tree, proto_item *option_item, tvbuff_t *tvb, int start_offset)
1984 int offset = start_offset;
1985 uint8_t opt_byte;
1986 const tn_opt *opt;
1987 int subneg_len;
1988 int iac_offset;
1989 unsigned len;
1990 tvbuff_t *unescaped_tvb;
1991 int cur_offset;
1992 bool iac_found;
1995 * As data with value iac (0xff) is possible, this value must be escaped
1996 * with iac (rfc 854).
1998 int iac_data = 0;
2000 offset += 2; /* skip IAC and SB */
2002 /* Get the option code */
2003 opt_byte = tvb_get_uint8(tvb, offset);
2004 opt = telnet_find_option(opt_byte);
2005 offset++;
2007 /* Search for an unescaped IAC. */
2008 cur_offset = offset;
2009 len = tvb_reported_length_remaining(tvb, offset);
2010 do {
2011 iac_offset = tvb_find_uint8(tvb, cur_offset, len, TN_IAC);
2012 iac_found = true;
2013 if (iac_offset == -1) {
2014 /* None found - run to the end of the packet. */
2015 offset += len;
2016 } else {
2017 if (!tvb_offset_exists(tvb, iac_offset + 1) ||
2018 (tvb_get_uint8(tvb, iac_offset + 1) != TN_IAC)) {
2019 /* We really found a single IAC, so we're done */
2020 offset = iac_offset;
2021 } else {
2023 * We saw an escaped IAC, so we have to move ahead to the
2024 * next section
2026 iac_found = false;
2027 cur_offset = iac_offset + 2;
2028 iac_data += 1;
2032 } while (!iac_found);
2034 subneg_len = offset - start_offset;
2036 start_offset += 3; /* skip IAC, SB, and option code */
2037 subneg_len -= 3;
2039 if (subneg_len > 0) {
2041 /* Now dissect the suboption parameters. */
2042 if (opt->dissect != NULL) {
2044 switch (opt->len_type) {
2046 case NO_LENGTH:
2047 /* There isn't supposed to *be* sub-option negotiation for this. */
2048 expert_add_info_format(pinfo, option_item, &ei_telnet_suboption_length, "Bogus suboption data");
2049 return offset;
2051 case FIXED_LENGTH:
2052 /* Make sure the length is what it's supposed to be. */
2053 if (subneg_len - iac_data != opt->optlen) {
2054 expert_add_info_format(pinfo, option_item, &ei_telnet_suboption_length, "Suboption parameter length is %d, should be %d", subneg_len, opt->optlen);
2055 return offset;
2057 break;
2059 case VARIABLE_LENGTH:
2060 /* Make sure the length is greater than the minimum. */
2061 if (subneg_len - iac_data < opt->optlen) {
2062 expert_add_info_format(pinfo, option_item, &ei_telnet_suboption_length, "Suboption parameter length is %d, should be at least %d", subneg_len, opt->optlen);
2063 return offset;
2065 break;
2068 /* We have a dissector for this suboption's parameters; call it. */
2069 if (iac_data > 0) {
2070 /* Data is escaped, we have to unescape it. */
2071 unescaped_tvb = unescape_and_tvbuffify_telnet_option(pinfo, tvb, start_offset, subneg_len);
2072 (*opt->dissect)(pinfo, opt->name, unescaped_tvb, 0, subneg_len - iac_data, option_tree, option_item);
2073 } else {
2074 (*opt->dissect)(pinfo, opt->name, tvb, start_offset, subneg_len, option_tree, option_item);
2076 } else {
2077 /* We don't have a dissector for them; just show them as data. */
2078 if (iac_data > 0) {
2079 /* Data is escaped, we have to unescape it. */
2080 unescaped_tvb = unescape_and_tvbuffify_telnet_option(pinfo, tvb, start_offset, subneg_len);
2081 proto_tree_add_item(option_tree, hf_telnet_option_data, unescaped_tvb, 0, subneg_len - iac_data, ENC_NA);
2082 } else {
2083 proto_tree_add_item(option_tree, hf_telnet_option_data, tvb, start_offset, subneg_len, ENC_NA);
2087 return offset;
2090 static void
2091 telnet_suboption_name(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int* offset, const char** optname,
2092 proto_tree **opt_tree, proto_item **opt_item, const char *type)
2094 uint8_t opt_byte;
2095 const tn_opt *opt;
2096 int ett = ett_telnet_subopt;
2098 opt_byte = tvb_get_uint8(tvb, *offset);
2099 opt = telnet_find_option(opt_byte);
2100 if (opt->subtree_index != NULL)
2101 ett = *(opt->subtree_index);
2102 *opt_item = proto_tree_add_uint_format_value(tree, hf_telnet_subcmd, tvb, *offset, 1, opt_byte, "%s", opt->name);
2103 *opt_tree = proto_item_add_subtree(*opt_item, ett);
2105 (*offset)++;
2106 (*optname) = wmem_strdup_printf(pinfo->pool, "%s %s", type, opt->name);
2109 static int
2110 telnet_command(packet_info *pinfo, proto_tree *telnet_tree, tvbuff_t *tvb, int start_offset, unsigned *num_info_items)
2112 int offset = start_offset;
2113 unsigned char optcode;
2114 const char* optname;
2115 proto_item *cmd_item, *subopt_item = NULL;
2116 proto_tree *cmd_tree, *subopt_tree = NULL;
2118 offset += 1; /* skip IAC */
2119 optcode = tvb_get_uint8(tvb, offset);
2121 cmd_tree = proto_tree_add_subtree(telnet_tree, tvb, start_offset, 2, ett_telnet_cmd, &cmd_item, "Command header");
2122 proto_tree_add_item(cmd_tree, hf_telnet_cmd, tvb, offset, 1, ENC_BIG_ENDIAN);
2123 offset++;
2125 switch(optcode) {
2126 case TN_WILL:
2127 telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Will");
2128 break;
2130 case TN_WONT:
2131 telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Won't");
2132 break;
2134 case TN_DO:
2135 telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Do");
2136 break;
2138 case TN_DONT:
2139 telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Don't");
2140 break;
2142 case TN_SB:
2143 telnet_suboption_name(cmd_tree, pinfo, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Suboption");
2144 break;
2146 default:
2147 optname = val_to_str_const(optcode, cmd_vals, "<unknown option>");
2148 break;
2151 proto_item_set_text(cmd_item, "%s", optname);
2152 if (optcode != TN_SE) {
2153 add_telnet_info_str(pinfo, num_info_items, optname);
2156 if (optcode == TN_SB) {
2157 offset = telnet_sub_option(pinfo, subopt_tree, subopt_item, tvb, start_offset);
2160 proto_item_set_len(cmd_item, offset-start_offset);
2162 return offset;
2165 static void
2166 telnet_add_text(proto_tree *tree, tvbuff_t *tvb, int offset, int len)
2168 int next_offset;
2169 int linelen;
2170 uint8_t c;
2171 bool last_char_was_cr;
2173 while (len != 0 && tvb_offset_exists(tvb, offset)) {
2175 * Find the end of the line.
2177 linelen = tvb_find_line_end(tvb, offset, len, &next_offset, false);
2178 len -= next_offset - offset; /* subtract out the line's characters */
2181 * In Telnet, CR NUL is the way you send a CR by itself in the
2182 * default ASCII mode; don't treat CR by itself as a line ending,
2183 * treat only CR NUL, CR LF, or LF by itself as a line ending.
2185 if (next_offset == offset + linelen + 1 && len >= 1) {
2187 * Well, we saw a one-character line ending, so either it's a CR
2188 * or an LF; we have at least two characters left, including the
2189 * CR.
2191 * If the line ending is a CR, skip all subsequent CRs; at
2192 * least one capture appeared to have multiple CRs at the end of
2193 * a line.
2195 if (tvb_get_uint8(tvb, offset + linelen) == '\r') {
2196 last_char_was_cr = true;
2197 while (len != 0 && tvb_offset_exists(tvb, next_offset)) {
2198 c = tvb_get_uint8(tvb, next_offset);
2199 next_offset++; /* skip over that character */
2200 len--;
2201 if (c == '\n' || (c == '\0' && last_char_was_cr)) {
2203 * LF is a line ending, whether preceded by CR or not.
2204 * NUL is a line ending if preceded by CR.
2206 break;
2208 last_char_was_cr = (c == '\r');
2214 * Now compute the length of the line *including* the end-of-line
2215 * indication, if any; we display it all.
2217 linelen = next_offset - offset;
2219 proto_tree_add_item(tree, hf_telnet_data, tvb, offset, linelen, ENC_ASCII);
2220 offset = next_offset;
2224 static int find_unescaped_iac(tvbuff_t *tvb, int offset, int len)
2226 int iac_offset = offset;
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 while ((iac_offset = tvb_find_uint8(tvb, iac_offset, len, TN_IAC)) != -1 &&
2231 (tvb_get_uint8(tvb, iac_offset + 1) == TN_IAC))
2233 iac_offset+=2;
2234 len = tvb_reported_length_remaining(tvb, iac_offset);
2236 return iac_offset;
2239 static int
2240 dissect_telnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2242 proto_tree *telnet_tree, *ti;
2243 tvbuff_t *next_tvb;
2244 int offset = 0;
2245 unsigned len = 0;
2246 unsigned is_tn3270 = 0;
2247 unsigned is_tn5250 = 0;
2248 int data_len;
2249 int iac_offset;
2250 unsigned num_info_items = 0;
2252 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TELNET");
2253 col_set_str(pinfo->cinfo, COL_INFO, "Telnet Data" UTF8_HORIZONTAL_ELLIPSIS);
2255 is_tn3270 = find_tn3270_conversation(pinfo);
2256 is_tn5250 = find_tn5250_conversation(pinfo);
2258 ti = proto_tree_add_item(tree, proto_telnet, tvb, offset, -1, ENC_NA);
2259 telnet_tree = proto_item_add_subtree(ti, ett_telnet);
2262 * Scan through the buffer looking for an IAC byte.
2264 while ((len = tvb_reported_length_remaining(tvb, offset)) > 0) {
2265 iac_offset = find_unescaped_iac(tvb, offset, len);
2266 if (iac_offset != -1) {
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.
2272 data_len = iac_offset - offset;
2273 if (data_len > 0) {
2274 add_telnet_data_bytes_str(pinfo, &num_info_items, data_len);
2275 if (is_tn3270) {
2276 next_tvb = tvb_new_subset_length(tvb, offset, data_len);
2277 call_dissector(tn3270_handle, next_tvb, pinfo, telnet_tree);
2278 } else if (is_tn5250) {
2279 next_tvb = tvb_new_subset_length(tvb, offset, data_len);
2280 call_dissector(tn5250_handle, next_tvb, pinfo, telnet_tree);
2281 } else
2282 telnet_add_text(telnet_tree, tvb, offset, data_len);
2285 * Now interpret the command.
2287 offset = telnet_command(pinfo, telnet_tree, tvb, iac_offset, &num_info_items);
2288 } else {
2289 /* get more data if tn3270 */
2290 if (is_tn3270 || is_tn5250) {
2291 pinfo->desegment_offset = offset;
2292 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
2293 return tvb_captured_length(tvb);
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.
2300 if (len > 0) {
2301 add_telnet_data_bytes_str(pinfo, &num_info_items, len);
2302 telnet_add_text(telnet_tree, tvb, offset, len);
2304 break;
2307 return tvb_captured_length(tvb);
2310 void
2311 proto_register_telnet(void)
2313 static hf_register_info hf[] = {
2314 { &hf_telnet_cmd,
2315 { "Command", "telnet.cmd", FT_UINT8, BASE_DEC,
2316 VALS(cmd_vals), 0, NULL, HFILL }
2318 { &hf_telnet_subcmd,
2319 { "Subcommand", "telnet.subcmd", FT_UINT8, BASE_DEC,
2320 NULL, 0, NULL, HFILL }
2322 { &hf_telnet_auth_name,
2323 { "Name", "telnet.auth.name", FT_STRING, BASE_NONE,
2324 NULL, 0, "Name of user being authenticated", HFILL }
2326 { &hf_telnet_auth_cmd,
2327 { "Auth Cmd", "telnet.auth.cmd", FT_UINT8, BASE_DEC,
2328 VALS(auth_cmd_vals), 0, "Authentication Command", HFILL }
2330 { &hf_telnet_auth_type,
2331 { "Auth Type", "telnet.auth.type", FT_UINT8, BASE_DEC,
2332 VALS(auth_type_vals), 0, "Authentication Type", HFILL }
2334 { &hf_telnet_auth_mod_cred_fwd,
2335 { "Cred Fwd", "telnet.auth.mod.cred_fwd", FT_BOOLEAN, 8,
2336 TFS(&auth_mod_cred_fwd), 0x08, "Modifier: Whether client will forward creds or not", HFILL }
2338 { &hf_telnet_auth_mod_who,
2339 { "Who", "telnet.auth.mod.who", FT_BOOLEAN, 8,
2340 TFS(&tfs_s2c_c2s), 0x01, "Modifier: Who will authenticate", HFILL }
2342 { &hf_telnet_auth_mod_how,
2343 { "How", "telnet.auth.mod.how", FT_BOOLEAN, 8,
2344 TFS(&auth_mod_how), 0x02, "Modifier: Authentication flow", HFILL }
2346 { &hf_telnet_auth_mod_enc,
2347 { "Encrypt", "telnet.auth.mod.enc", FT_UINT8, BASE_DEC,
2348 VALS(auth_mod_enc), 0x14, "Modifier: How to enable Encryption", HFILL }
2350 { &hf_telnet_auth_krb5_type,
2351 { "Command", "telnet.auth.krb5.cmd", FT_UINT8, BASE_DEC,
2352 VALS(auth_krb5_types), 0, "Krb5 Authentication sub-command", HFILL }
2354 { &hf_telnet_auth_ssl_status,
2355 { "Status", "telnet.auth.ssl.status", FT_UINT8, BASE_DEC,
2356 VALS(ssl_auth_status), 0, "SSL authentication status", HFILL }
2358 { &hf_telnet_auth_data,
2359 { "Authentication data", "telnet.auth.data", FT_BYTES, BASE_NONE,
2360 NULL, 0, NULL, HFILL }
2362 { &hf_telnet_string_subopt_value,
2363 { "Value", "telnet.string_subopt.value", FT_STRING, BASE_NONE,
2364 NULL, 0, NULL, HFILL }
2366 { &hf_telnet_naws_subopt_width,
2367 { "Width", "telnet.naws_subopt.width", FT_UINT16, BASE_DEC,
2368 NULL, 0, NULL, HFILL }
2370 { &hf_telnet_naws_subopt_height,
2371 { "Height", "telnet.naws_subopt.height", FT_UINT16, BASE_DEC,
2372 NULL, 0, NULL, HFILL }
2374 { &hf_telnet_outmark_subopt_cmd,
2375 { "Command", "telnet.outmark_subopt.cmd", FT_CHAR, BASE_HEX,
2376 VALS(telnet_outmark_subopt_cmd_vals), 0, NULL, HFILL }
2378 { &hf_telnet_outmark_subopt_banner,
2379 { "Banner", "telnet.outmark_subopt.banner", FT_STRING, BASE_NONE,
2380 NULL, 0, NULL, HFILL }
2382 { &hf_telnet_comport_subopt_signature,
2383 { "Signature", "telnet.comport_subopt.signature", FT_STRING, BASE_NONE,
2384 NULL, 0, NULL, HFILL }
2386 { &hf_telnet_comport_subopt_baud_rate,
2387 { "Baud Rate", "telnet.comport_subopt.baud_rate", FT_UINT32, BASE_DEC,
2388 NULL, 0, NULL, HFILL }
2390 { &hf_telnet_comport_subopt_data_size,
2391 { "Data Size", "telnet.comport_subopt.data_size", FT_UINT8, BASE_DEC,
2392 NULL, 0, NULL, HFILL }
2394 { &hf_telnet_comport_subopt_parity,
2395 { "Parity", "telnet.comport_subopt.parity", FT_UINT16, BASE_DEC,
2396 NULL, 0, NULL, HFILL }
2398 { &hf_telnet_comport_subopt_stop,
2399 { "Stop Bits", "telnet.comport_subopt.stop", FT_UINT16, BASE_DEC,
2400 NULL, 0, NULL, HFILL }
2402 { &hf_telnet_comport_subopt_control,
2403 { "Control", "telnet.comport_subopt.control", FT_UINT16, BASE_DEC,
2404 NULL, 0, NULL, HFILL }
2406 { &hf_telnet_comport_linestate,
2407 { "Linestate", "telnet.comport_subopt.linestate", FT_STRING, BASE_NONE,
2408 NULL, 0, NULL, HFILL }
2410 { &hf_telnet_comport_set_linestate_mask,
2411 { "Set Linestate Mask", "telnet.comport_subopt.set_linestate_mask", FT_STRING, BASE_NONE,
2412 NULL, 0, NULL, HFILL }
2414 { &hf_telnet_comport_modemstate,
2415 { "Modemstate", "telnet.comport_subopt.modemstate", FT_STRING, BASE_NONE,
2416 NULL, 0, NULL, HFILL }
2418 { &hf_telnet_comport_set_modemstate_mask,
2419 { "Set Modemstate Mask", "telnet.comport_subopt.set_modemstate_mask", FT_STRING, BASE_NONE,
2420 NULL, 0, NULL, HFILL }
2422 { &hf_telnet_comport_subopt_flow_control_suspend,
2423 { "Flow Control Suspend", "telnet.comport_subopt.flow_control_suspend", FT_NONE, BASE_NONE,
2424 NULL, 0, NULL, HFILL }
2426 { &hf_telnet_comport_subopt_flow_control_resume,
2427 { "Flow Control Resume", "telnet.comport_subopt.flow_control_resume", FT_NONE, BASE_NONE,
2428 NULL, 0, NULL, HFILL }
2430 { &hf_telnet_comport_subopt_purge,
2431 { "Purge", "telnet.comport_subopt.purge", FT_UINT16, BASE_DEC,
2432 NULL, 0, NULL, HFILL }
2434 { &hf_telnet_rfc_subopt_cmd,
2435 { "Command", "telnet.rfc_subopt.cmd", FT_UINT8, BASE_DEC,
2436 VALS(rfc_opt_vals), 0, NULL, HFILL }
2438 { &hf_telnet_tabstop,
2439 { "Tabstop value", "telnet.tabstop", FT_UINT8, BASE_DEC,
2440 NULL, 0, NULL, HFILL }
2442 { &hf_telnet_enc_cmd,
2443 { "Enc Cmd", "telnet.enc.cmd", FT_UINT8, BASE_DEC,
2444 VALS(enc_cmd_vals), 0, "Encryption command", HFILL }
2446 { &hf_telnet_enc_type,
2447 { "Enc Type", "telnet.enc.type", FT_UINT8, BASE_DEC,
2448 VALS(enc_type_vals), 0, "Encryption type", HFILL }
2450 { &hf_telnet_enc_type_data,
2451 { "Type-specific data", "telnet.enc.type_data", FT_BYTES, BASE_NONE,
2452 NULL, 0, NULL, HFILL }
2454 { &hf_telnet_enc_key_id,
2455 { "Key ID", "telnet.enc.key_id", FT_BYTES, BASE_NONE,
2456 NULL, 0, NULL, HFILL }
2458 { &hf_telnet_data,
2459 { "Data", "telnet.data", FT_STRING, BASE_NONE,
2460 NULL, 0, NULL, HFILL }
2462 { &hf_telnet_option_data,
2463 { "Option data", "telnet.option_data", FT_BYTES, BASE_NONE,
2464 NULL, 0, NULL, HFILL }
2466 { &hf_telnet_subcommand_data,
2467 { "Subcommand data", "telnet.subcommand_data", FT_BYTES, BASE_NONE,
2468 NULL, 0, NULL, HFILL }
2470 { &hf_tn3270_subopt,
2471 { "Suboption", "telnet.tn3270.subopt", FT_UINT8, BASE_DEC,
2472 VALS(tn3270_subopt_vals), 0, NULL, HFILL }
2474 { &hf_tn3270_connect,
2475 { "Connect", "telnet.tn3270.connect", FT_STRING, BASE_NONE,
2476 NULL, 0, NULL, HFILL }
2478 { &hf_tn3270_is,
2479 { "Is", "telnet.tn3270.is", FT_STRING, BASE_NONE,
2480 NULL, 0, NULL, HFILL }
2482 { &hf_tn3270_request_string,
2483 { "Request", "telnet.tn3270.request_string", FT_STRING, BASE_NONE,
2484 NULL, 0, NULL, HFILL }
2486 { &hf_tn3270_reason,
2487 { "Reason", "telnet.tn3270.reason", FT_UINT8, BASE_DEC,
2488 VALS(tn3270_reason_vals), 0, NULL, HFILL }
2490 { &hf_tn3270_request,
2491 { "Request", "telnet.tn3270.request", FT_UINT8, BASE_DEC,
2492 VALS(tn3270_request_vals), 0, NULL, HFILL }
2494 { &hf_tn3270_regime_subopt_value,
2495 { "Value", "telnet.tn3270.regime_subopt.value", FT_STRING, BASE_NONE,
2496 NULL, 0, NULL, HFILL }
2498 { &hf_tn3270_regime_cmd,
2499 { "Cmd", "telnet.regime_cmd", FT_UINT8, BASE_DEC,
2500 NULL, 0, NULL, HFILL }
2502 { &hf_telnet_starttls,
2503 { "Follows", "telnet.starttls", FT_UINT8, BASE_DEC,
2504 NULL, 0, NULL, HFILL }
2506 { &hf_telnet_vmware_cmd,
2507 { "VMware Serial Port Proxy Cmd", "telnet.vmware.cmd", FT_UINT8, BASE_DEC,
2508 VALS(vmware_cmd_vals), 0, "VMware command", HFILL }
2510 { &hf_telnet_vmware_known_suboption_code,
2511 { "Suboption", "telnet.vmware.known_suboption_code", FT_UINT8, BASE_DEC,
2512 VALS(vmware_cmd_vals), 0, NULL, HFILL }
2514 { &hf_telnet_vmware_unknown_subopt_code,
2515 { "Code", "telnet.vmware.unknown_suboption_code", FT_UINT8, BASE_DEC,
2516 NULL, 0, NULL, HFILL }
2518 { &hf_telnet_vmware_vmotion_sequence,
2519 { "vMotion sequence", "telnet.vmware.vmotion.sequence", FT_BYTES, BASE_NONE,
2520 NULL, 0, NULL, HFILL }
2522 { &hf_telnet_vmware_vmotion_secret,
2523 { "vMotion secret", "telnet.vmware.vmotion.secret", FT_BYTES, BASE_NONE,
2524 NULL, 0, NULL, HFILL }
2526 { &hf_telnet_vmware_proxy_direction,
2527 { "Proxy Direction", "telnet.vmware.proxy.direction", FT_CHAR, BASE_HEX,
2528 VALS(vmware_proxy_direction_vals), 0, NULL, HFILL }
2530 { &hf_telnet_vmware_proxy_serviceUri,
2531 { "Proxy Service URI", "telnet.vmware.proxy.serviceUri", FT_STRING, BASE_NONE,
2532 NULL, 0, NULL, HFILL }
2534 { &hf_telnet_vmware_vm_vc_uuid,
2535 { "VM VC UUID", "telnet.vmware.vm.vc_uuid", FT_STRING, BASE_NONE,
2536 NULL, 0, NULL, HFILL }
2538 { &hf_telnet_vmware_vm_bios_uuid,
2539 { "VM BIOS UUID", "telnet.vmware.vm.bios_uuid", FT_STRING, BASE_NONE,
2540 NULL, 0, NULL, HFILL }
2542 { &hf_telnet_vmware_vm_location_uuid,
2543 { "VM Location UUID", "telnet.vmware.vm.location_uuid", FT_STRING, BASE_NONE,
2544 NULL, 0, NULL, HFILL }
2546 { &hf_telnet_vmware_vm_name,
2547 { "VM name", "telnet.vmware.vm.name", FT_STRING, BASE_NONE,
2548 NULL, 0, NULL, HFILL }
2551 static int *ett[] = {
2552 &ett_telnet,
2553 &ett_telnet_cmd,
2554 &ett_telnet_subopt,
2555 &ett_status_subopt,
2556 &ett_rcte_subopt,
2557 &ett_olw_subopt,
2558 &ett_ops_subopt,
2559 &ett_crdisp_subopt,
2560 &ett_htstops_subopt,
2561 &ett_htdisp_subopt,
2562 &ett_ffdisp_subopt,
2563 &ett_vtstops_subopt,
2564 &ett_vtdisp_subopt,
2565 &ett_lfdisp_subopt,
2566 &ett_extasc_subopt,
2567 &ett_bytemacro_subopt,
2568 &ett_det_subopt,
2569 &ett_supdupout_subopt,
2570 &ett_sendloc_subopt,
2571 &ett_termtype_subopt,
2572 &ett_tacacsui_subopt,
2573 &ett_outmark_subopt,
2574 &ett_tlocnum_subopt,
2575 &ett_tn3270reg_subopt,
2576 &ett_x3pad_subopt,
2577 &ett_naws_subopt,
2578 &ett_tspeed_subopt,
2579 &ett_rfc_subopt,
2580 &ett_linemode_subopt,
2581 &ett_xdpyloc_subopt,
2582 &ett_env_subopt,
2583 &ett_auth_subopt,
2584 &ett_enc_subopt,
2585 &ett_newenv_subopt,
2586 &ett_tn3270e_subopt,
2587 &ett_xauth_subopt,
2588 &ett_charset_subopt,
2589 &ett_rsp_subopt,
2590 &ett_comport_subopt,
2591 &ett_starttls_subopt,
2594 static ei_register_info ei[] = {
2595 { &ei_telnet_invalid_subcommand, { "telnet.invalid_subcommand", PI_PROTOCOL, PI_WARN, "Invalid subcommand", EXPFILL }},
2596 { &ei_telnet_invalid_baud_rate, { "telnet.invalid_baud_rate", PI_PROTOCOL, PI_WARN, "Invalid Baud Rate", EXPFILL }},
2597 { &ei_telnet_invalid_data_size, { "telnet.invalid_data_size", PI_PROTOCOL, PI_WARN, "Invalid Data Size", EXPFILL }},
2598 { &ei_telnet_invalid_parity, { "telnet.invalid_parity", PI_PROTOCOL, PI_WARN, "Invalid Parity Packet", EXPFILL }},
2599 { &ei_telnet_invalid_stop, { "telnet.invalid_stop", PI_PROTOCOL, PI_WARN, "Invalid Stop Packet", EXPFILL }},
2600 { &ei_telnet_invalid_control, { "telnet.invalid_control", PI_PROTOCOL, PI_WARN, "Invalid Control Packet", EXPFILL }},
2601 { &ei_telnet_invalid_linestate, { "telnet.invalid_linestate", PI_PROTOCOL, PI_WARN, "Invalid linestate", EXPFILL }},
2602 { &ei_telnet_invalid_modemstate, { "telnet.invalid_modemstate", PI_PROTOCOL, PI_WARN, "Invalid Modemstate", EXPFILL }},
2603 { &ei_telnet_invalid_purge, { "telnet.invalid_purge", PI_PROTOCOL, PI_WARN, "Invalid Purge Packet", EXPFILL }},
2604 { &ei_telnet_enc_cmd_unknown, { "telnet.enc.cmd.unknown", PI_PROTOCOL, PI_WARN, "Unknown encryption command", EXPFILL }},
2605 { &ei_telnet_suboption_length, { "telnet.suboption_length.invalid", PI_PROTOCOL, PI_WARN, "Bogus suboption data", EXPFILL }},
2606 { &ei_telnet_vmware_unexp_data, { "telnet.vmware.unexpected_data", PI_PROTOCOL, PI_WARN, "Unexpected VMware Serial Port Proxy negotiation data", EXPFILL }},
2609 expert_module_t* expert_telnet;
2611 proto_telnet = proto_register_protocol("Telnet", "TELNET", "telnet");
2612 proto_register_field_array(proto_telnet, hf, array_length(hf));
2613 proto_register_subtree_array(ett, array_length(ett));
2615 expert_telnet = expert_register_protocol(proto_telnet);
2616 expert_register_field_array(expert_telnet, ei, array_length(ei));
2618 telnet_handle = register_dissector("telnet", dissect_telnet, proto_telnet);
2621 void
2622 proto_reg_handoff_telnet(void)
2624 dissector_add_uint_with_preference("tcp.port", TCP_PORT_TELNET, telnet_handle);
2626 dissector_add_uint("acdr.tls_application", TLS_APP_TELNET, telnet_handle);
2628 tn3270_handle = find_dissector_add_dependency("tn3270", proto_telnet);
2629 tn5250_handle = find_dissector_add_dependency("tn5250", proto_telnet);
2630 tls_handle = find_dissector("tls");
2634 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2636 * Local Variables:
2637 * c-basic-offset: 2
2638 * tab-width: 8
2639 * indent-tabs-mode: nil
2640 * End:
2642 * ex: set shiftwidth=2 tabstop=8 expandtab:
2643 * :indentSize=2:tabSize=8:noTabs=true: