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
19 #include <epan/packet.h>
20 #include <epan/expert.h>
21 #include <epan/asn1.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
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" },
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" },
205 { TN_WONT
, "Won't" },
207 { TN_SB
, "Suboption" },
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 */
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 */
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
;
234 check_tn3270_model(packet_info
*pinfo _U_
, const char *terminaltype
)
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
);
250 check_for_tn3270(packet_info
*pinfo _U_
, const char *optname
, const char *terminaltype
)
252 if (strcmp(optname
,"Terminal Type") != 0) {
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
);
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
);
285 /* Record some data/negotiation/subnegotiation in the "Info" column. */
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
);
303 /* Record in the "Info" column that a number of Telnet data bytes arrived. */
305 add_telnet_data_bytes_str(packet_info
*pinfo
, unsigned *num_items
, unsigned len
)
309 snprintf(str
, sizeof str
, "%u byte%s data", len
, plurality(len
, "", "s"));
310 add_telnet_info_str(pinfo
, num_items
, str
);
314 dissect_string_subopt(packet_info
*pinfo
, const char *optname
, tvbuff_t
*tvb
, int offset
, int len
,
315 proto_tree
*tree
, proto_item
*item
)
319 cmd
= tvb_get_uint8(tvb
, offset
);
323 proto_tree_add_uint_format(tree
, hf_telnet_subcmd
, tvb
, offset
, 1, cmd
, "Here's my %s", optname
);
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
));
333 proto_tree_add_uint_format(tree
, hf_telnet_subcmd
, tvb
, offset
, 1, cmd
, "Send your %s", optname
);
337 proto_tree_add_bytes_format(tree
, hf_telnet_subcommand_data
, tvb
, offset
, len
, NULL
, "Extra data");
341 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_subcommand
, "Invalid %s subcommand %u", optname
, cmd
);
346 proto_tree_add_item(tree
, hf_telnet_subcommand_data
, tvb
, offset
, len
, ENC_NA
);
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
361 cmd
= tvb_get_uint8(tvb
, offset
);
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);
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
);
374 proto_tree_add_uint_format(tree
, hf_tn3270_regime_cmd
, tvb
, offset
, 1, cmd
, "Bogus value: %u", cmd
);
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
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
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" },
414 { TN3270_REASON
, "REASON" },
415 { TN3270_REJECT
, "REJECT" },
416 { TN3270_REQUEST
, "REQUEST" },
417 { TN3270_SEND
, "SEND" },
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" },
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" },
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_
)
449 int connect_offset
= 0;
454 cmd
= tvb_get_uint8(tvb
, offset
);
455 proto_tree_add_item( tree
, hf_tn3270_subopt
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
458 proto_tree_add_item( tree
, hf_tn3270_connect
, tvb
, offset
+ 1, len
, ENC_NA
|ENC_ASCII
);
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);
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
));
481 proto_tree_add_item( tree
, hf_tn3270_reason
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
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
);
490 }else if (device_type
== TN3270_FUNCTIONS
) {
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
)
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
[] = {
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
;
546 proto_tree_add_item(tree
, hf_telnet_outmark_subopt_cmd
, tvb
, offset
, 1, ENC_ASCII
| ENC_NA
);
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
;
559 proto_tree_add_item(tree
, hf_telnet_outmark_subopt_banner
, tvb
, offset
, datalen
, ENC_NA
|ENC_ASCII
);
567 dissect_htstops_subopt(packet_info
*pinfo
, const char *optname
, tvbuff_t
*tvb
, int offset
, int len
,
568 proto_tree
*tree
, proto_item
*item
)
573 cmd
= tvb_get_uint8(tvb
, offset
);
577 proto_tree_add_uint_format(tree
, hf_telnet_subcmd
, tvb
, offset
, 1, cmd
, "Here's my %s", optname
);
583 proto_tree_add_uint_format(tree
, hf_telnet_subcmd
, tvb
, offset
, 1, cmd
, "Send your %s", optname
);
589 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_subcommand
, "Invalid %s subcommand %u", optname
, cmd
);
593 proto_tree_add_item(tree
, hf_telnet_subcommand_data
, tvb
, offset
, len
, ENC_NA
);
598 tabval
= tvb_get_uint8(tvb
, offset
);
602 proto_tree_add_uint_format(tree
, hf_telnet_tabstop
, tvb
, offset
, 1,
603 tabval
, "Sender wants to handle tab stops");
607 proto_tree_add_uint_format(tree
, hf_telnet_tabstop
, tvb
, offset
, 1,
608 tabval
, "Sender wants receiver to handle tab stop at %u",
616 proto_tree_add_uint_format(tree
, hf_telnet_tabstop
, tvb
, offset
, 1,
617 tabval
, "Invalid value: %u", tabval
);
621 proto_tree_add_uint_format(tree
, hf_telnet_tabstop
, tvb
, offset
, 1,
622 tabval
, "Sender wants receiver to handle tab stops");
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
);
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 */
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
[] = {
672 static const char *parities
[] = {
680 static const char *stops
[] = {
686 static const char *control
[] = {
687 "Output Flow Control Request",
689 "Output Flow: XON/XOFF",
690 "Output Flow: CTS/RTS",
700 "Input Flow Control Request",
702 "Input Flow: XON/XOFF",
703 "Input Flow: CTS/RTS",
708 static const char *linestate_bits
[] = {
714 "Transfer Holding Register Empty",
715 "Transfer Shift Register Empty",
718 static const char *modemstate_bits
[] = {
728 static const char *purges
[] = {
739 cmd
= tvb_get_uint8(tvb
, offset
);
740 isservercmd
= cmd
> 99;
741 cmd
= (isservercmd
) ? (cmd
- 100) : cmd
;
742 source
= (isservercmd
) ? "Server" : "Client";
744 case TNCOMPORT_SIGNATURE
:
747 proto_tree_add_string_format(tree
, hf_telnet_comport_subopt_signature
, tvb
, offset
, 1, "", "%s Requests Signature", source
);
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
);
755 case TNCOMPORT_SETBAUDRATE
:
758 uint32_t baud
= tvb_get_ntohl(tvb
, offset
+1);
760 proto_tree_add_uint_format_value(tree
, hf_telnet_comport_subopt_baud_rate
, tvb
, offset
, 5, 0, "%s Requests Baud Rate",source
);
762 proto_tree_add_uint_format_value(tree
, hf_telnet_comport_subopt_baud_rate
, tvb
, offset
, 5, baud
, "%s Baud Rate: %d",source
,baud
);
765 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_baud_rate
, "%s <Invalid Baud Rate Packet>", source
);
769 case TNCOMPORT_SETDATASIZE
:
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
);
777 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_data_size
, "%s <Invalid Data Size Packet>", source
);
781 case TNCOMPORT_SETPARITY
:
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
);
789 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_parity
, "%s <Invalid Parity Packet>", source
);
792 case TNCOMPORT_SETSTOPSIZE
:
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
);
800 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_stop
, "%s <Invalid Stop Packet>", source
);
804 case TNCOMPORT_SETCONTROL
:
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
);
812 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_control
, "%s <Invalid Control Packet>", source
);
816 case TNCOMPORT_SETLINESTATEMASK
:
817 case TNCOMPORT_NOTIFYLINESTATE
:
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
;
825 uint8_t ls
= tvb_get_uint8(tvb
, offset
+1);
829 for (idx
= 0; idx
< 8; idx
++) {
832 if (print_count
!= 0) {
833 (void) g_strlcat(ls_buffer
,", ",512);
835 (void) g_strlcat(ls_buffer
,linestate_bits
[idx
], 512);
840 proto_tree_add_string_format(tree
, hf_line
, tvb
, offset
, 2, ls_buffer
, print_pattern
, source
, ls_buffer
);
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
);
848 case TNCOMPORT_SETMODEMSTATEMASK
:
849 case TNCOMPORT_NOTIFYMODEMSTATE
:
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
;
857 uint8_t ms
= tvb_get_uint8(tvb
, offset
+1);
861 for (idx
= 0; idx
< 8; idx
++) {
864 if (print_count
!= 0) {
865 (void) g_strlcat(ms_buffer
,", ",256);
867 (void) g_strlcat(ms_buffer
,modemstate_bits
[idx
],256);
872 proto_tree_add_string_format(tree
, hf_modem
, tvb
, offset
, 2, ms_buffer
, print_pattern
, source
, ms_buffer
);
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
);
880 case TNCOMPORT_FLOWCONTROLSUSPEND
:
882 proto_tree_add_none_format(tree
, hf_telnet_comport_subopt_flow_control_suspend
, tvb
, offset
, 1, "%s Flow Control Suspend",source
);
885 case TNCOMPORT_FLOWCONTROLRESUME
:
887 proto_tree_add_none_format(tree
, hf_telnet_comport_subopt_flow_control_resume
, tvb
, offset
, 1, "%s Flow Control Resume",source
);
890 case TNCOMPORT_PURGEDATA
:
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
,
898 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_purge
, "%s <Invalid Purge Packet>", source
);
903 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_subcommand
, "Invalid %s subcommand %u", optname
, cmd
);
907 proto_tree_add_item(tree
, hf_telnet_subcommand_data
, tvb
, offset
, len
, ENC_NA
);
913 static const value_string rfc_opt_vals
[] = {
916 { 2, "RESTART-ANY" },
917 { 3, "RESTART-XON" },
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
);
929 #define TN_ENC_SUPPORT 1
930 #define TN_ENC_REPLY 2
931 #define TN_ENC_START 3
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
[] = {
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" },
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" },
975 #define TN_AC_REPLY 2
977 static const value_string auth_cmd_vals
[] = {
979 { TN_AC_SEND
, "SEND" },
980 { TN_AC_REPLY
, "REPLY" },
981 { TN_AC_NAME
, "NAME" },
993 #define TN_AT_LOKI 10
995 #define TN_AT_KEA_SJ 12
996 #define TN_AT_KEA_SJ_INTEG 13
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" },
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" },
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" },
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
,
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
1071 unescape_and_tvbuffify_telnet_option(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int len
)
1073 tvbuff_t
*option_subneg_tvb
;
1075 const uint8_t *spos
;
1079 if(len
>= MAX_TELNET_OPTION_SUBNEG_LEN
)
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
);
1089 // XXX Add expert info if spos >= last_src_pos?
1090 if(spos
< last_src_pos
&& (spos
[0] == 0xff) && (spos
[1] == 0xff)) {
1097 *(dpos
++) = *(spos
++);
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 */
1109 dissect_krb5_authentication_data(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int len
, proto_tree
*tree
, uint8_t acmd
)
1114 krb5_cmd
=tvb_get_uint8(tvb
, offset
);
1115 proto_tree_add_uint(tree
, hf_telnet_auth_krb5_type
, tvb
, offset
, 1, krb5_cmd
);
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
)){
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*/
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
)){
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" },
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 */
1187 dissect_authentication_data(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int len
, proto_tree
*tree
, uint8_t acmd
)
1191 dissect_authentication_type_pair(pinfo
, tvb
, offset
, tree
);
1192 auth_type
= tvb_get_uint8(tvb
, offset
);
1196 switch (auth_type
) {
1201 dissect_ssl_authentication_data(pinfo
, tvb
, offset
, tree
, acmd
);
1205 dissect_krb5_authentication_data(pinfo
, tvb
, offset
, len
, tree
, acmd
);
1209 /* We don't (yet) know how to dissect the data for this authentication type. */
1211 proto_tree_add_bytes_format(tree
, hf_telnet_auth_data
, tvb
, offset
, len
, NULL
, "Unhandled authentication data");
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_
)
1221 acmd
=tvb_get_uint8(tvb
, offset
);
1222 proto_tree_add_uint(tree
, hf_telnet_auth_cmd
, tvb
, offset
, 1, acmd
);
1229 dissect_authentication_data(pinfo
, tvb
, offset
, len
, tree
, acmd
);
1234 dissect_authentication_type_pair(pinfo
, tvb
, offset
, tree
);
1241 proto_tree_add_item(tree
, hf_telnet_auth_name
, tvb
, offset
, len
, ENC_ASCII
);
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
) {
1249 etype
= tvb_get_uint8(tvb
, offset
);
1250 proto_tree_add_uint(tree
, hf_telnet_enc_type
, tvb
, offset
, 1, etype
);
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
);
1268 /* encryption type, type-specific data ... */
1270 dissect_encryption_type(tvb
, offset
, tree
);
1273 proto_tree_add_item(tree
, hf_telnet_enc_type_data
, tvb
, offset
, len
, ENC_NA
);
1277 case TN_ENC_SUPPORT
:
1278 /* list of encryption types ... */
1280 dissect_encryption_type(tvb
, offset
, tree
);
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");
1298 case TN_ENC_REQUEST_START
:
1299 /* (optional) keyid */
1301 proto_tree_add_bytes_format(tree
, hf_telnet_enc_key_id
, tvb
, offset
, len
, NULL
, "Key ID (advisory)");
1304 case TN_ENC_REQUEST_END
:
1308 case TN_ENC_ENC_KEYID
:
1309 case TN_ENC_DEC_KEYID
:
1310 /* (optional) keyid - if not supplied, there are no more known keys */
1312 proto_tree_add_item(tree
, hf_telnet_enc_key_id
, tvb
, offset
, len
, ENC_NA
);
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" },
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" },
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
1402 vmwcmd
= tvb_get_uint8(tvb
, offset
);
1403 proto_tree_add_uint(tree
, hf_telnet_vmware_cmd
, tvb
, offset
, 1, vmwcmd
);
1409 /* --- Option Subnegotiation --- */
1411 case VMWARE_KNOWN_SUBOPTIONS_1
:
1412 case VMWARE_KNOWN_SUBOPTIONS_2
:
1413 /* Data: suboptions... */
1415 proto_tree_add_item(tree
, hf_telnet_vmware_known_suboption_code
, tvb
, offset
, 1, ENC_NA
);
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
);
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
);
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] = {
1474 .val
= tvb_memdup(pinfo
->pool
, tvb
, offset
, 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
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
);
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.
1529 case VMWARE_VMOTION_ABORT
:
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
);
1540 proto_tree_add_item(tree
, hf_telnet_vmware_proxy_serviceUri
, tvb
, offset
, len
, ENC_UTF_8
);
1545 case VMWARE_WILL_PROXY
:
1546 case VMWARE_WONT_PROXY
:
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
:
1559 case VMWARE_VM_NAME
:
1561 proto_tree_add_item(tree
, hf_telnet_vmware_vm_name
, tvb
, offset
, len
, ENC_UTF_8
);
1566 case VMWARE_VM_VC_UUID
:
1568 proto_tree_add_item(tree
, hf_telnet_vmware_vm_vc_uuid
, tvb
, offset
, len
, ENC_ASCII
);
1573 case VMWARE_VM_BIOS_UUID
:
1575 proto_tree_add_item(tree
, hf_telnet_vmware_vm_bios_uuid
, tvb
, offset
, len
, ENC_ASCII
);
1580 case VMWARE_VM_LOCATION_UUID
:
1582 proto_tree_add_item(tree
, hf_telnet_vmware_vm_location_uuid
, tvb
, offset
, len
, ENC_ASCII
);
1588 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_subcommand
, "Invalid %s subcommand %u", optname
, vmwcmd
);
1590 proto_tree_add_item(tree
, hf_telnet_subcommand_data
, tvb
, offset
, len
, ENC_NA
);
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 */
1608 "Echo", /* RFC 857 */
1609 NULL
, /* no suboption negotiation */
1615 "Reconnection", /* DOD Protocol Handbook */
1622 "Suppress Go Ahead", /* RFC 858 */
1623 NULL
, /* no suboption negotiation */
1629 "Approx Message Size Negotiation", /* Ethernet spec(!) */
1636 "Status", /* RFC 859 */
1640 NULL
/* XXX - fill me in */
1643 "Timing Mark", /* RFC 860 */
1644 NULL
, /* no suboption negotiation */
1650 "Remote Controlled Trans and Echo", /* RFC 726 */
1654 NULL
/* XXX - fill me in */
1657 "Output Line Width", /* DOD Protocol Handbook */
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 */
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 */
1675 NULL
/* XXX - fill me in */
1678 "Output Horizontal Tab Stops", /* RFC 653 */
1679 &ett_htstops_subopt
,
1682 dissect_htstops_subopt
1685 "Output Horizontal Tab Disposition", /* RFC 654 */
1689 NULL
/* XXX - fill me in */
1692 "Output Formfeed Disposition", /* RFC 655 */
1696 NULL
/* XXX - fill me in */
1699 "Output Vertical Tabstops", /* RFC 656 */
1700 &ett_vtstops_subopt
,
1703 NULL
/* XXX - fill me in */
1706 "Output Vertical Tab Disposition", /* RFC 657 */
1710 NULL
/* XXX - fill me in */
1713 "Output Linefeed Disposition", /* RFC 658 */
1717 NULL
/* XXX - fill me in */
1720 "Extended ASCII", /* RFC 698 */
1724 NULL
/* XXX - fill me in */
1727 "Logout", /* RFC 727 */
1728 NULL
, /* no suboption negotiation */
1734 "Byte Macro", /* RFC 735 */
1735 &ett_bytemacro_subopt
,
1738 NULL
/* XXX - fill me in */
1741 "Data Entry Terminal", /* RFC 732, RFC 1043 */
1745 NULL
/* XXX - fill me in */
1748 "SUPDUP", /* RFC 734, RFC 736 */
1749 NULL
, /* no suboption negotiation */
1755 "SUPDUP Output", /* RFC 749 */
1756 &ett_supdupout_subopt
,
1759 NULL
/* XXX - fill me in */
1762 "Send Location", /* RFC 779 */
1763 &ett_sendloc_subopt
,
1766 NULL
/* XXX - fill me in */
1769 "Terminal Type", /* RFC 1091 */
1770 &ett_termtype_subopt
,
1773 dissect_string_subopt
1776 "End of Record", /* RFC 885 */
1777 NULL
, /* no suboption negotiation */
1783 "TACACS User Identification", /* RFC 927 */
1784 &ett_tacacsui_subopt
,
1787 NULL
/* XXX - fill me in */
1790 "Output Marking", /* RFC 933 */
1791 &ett_outmark_subopt
,
1794 dissect_outmark_subopt
,
1797 "Terminal Location Number", /* RFC 946 */
1798 &ett_tlocnum_subopt
,
1801 NULL
/* XXX - fill me in */
1804 "Telnet 3270 Regime", /* RFC 1041 */
1805 &ett_tn3270reg_subopt
,
1808 dissect_tn3270_regime_subopt
1811 "X.3 PAD", /* RFC 1053 */
1815 NULL
/* XXX - fill me in */
1818 "Negotiate About Window Size", /* RFC 1073, DW183 */
1825 "Terminal Speed", /* RFC 1079 */
1829 NULL
/* XXX - fill me in */
1832 "Remote Flow Control", /* RFC 1372 */
1839 "Linemode", /* RFC 1184 */
1840 &ett_linemode_subopt
,
1843 NULL
/* XXX - fill me in */
1846 "X Display Location", /* RFC 1096 */
1847 &ett_xdpyloc_subopt
,
1850 dissect_string_subopt
1853 "Environment Option", /* RFC 1408, RFC 1571 */
1857 NULL
/* XXX - fill me in */
1860 "Authentication Option", /* RFC 2941 */
1864 dissect_authentication_subopt
1867 "Encryption Option", /* RFC 2946 */
1871 dissect_encryption_subopt
1874 "New Environment Option", /* RFC 1572 */
1878 NULL
/* XXX - fill me in */
1881 "TN3270E", /* RFC 1647 */
1882 &ett_tn3270e_subopt
,
1885 dissect_tn3270e_subopt
1888 "XAUTH", /* XAUTH */
1892 NULL
/* XXX - fill me in */
1895 "CHARSET", /* CHARSET */
1896 &ett_charset_subopt
,
1899 NULL
/* XXX - fill me in */
1902 "Remote Serial Port", /* Remote Serial Port */
1906 NULL
/* XXX - fill me in */
1909 "COM Port Control", /* RFC 2217 */
1910 &ett_comport_subopt
,
1913 dissect_comport_subopt
1916 "Suppress Local Echo", /* draft-rfced-exp-atmar-00 */
1923 "Start TLS", /* draft-ietf-tn3270e-telnet-tls-06 */
1924 &ett_starttls_subopt
,
1927 dissect_starttls_subopt
1930 "KERMIT", /* RFC 2840 */
1934 NULL
/* XXX - stub */
1937 "SEND-URL", /* draft-croft-telnet-url-trans-00 */
1941 NULL
/* XXX - stub */
1944 "FORWARD_X", /* draft-altman-telnet-fwdx-03 */
1948 NULL
/* XXX - stub */
1953 static const tn_opt telnet_opt_vmware
= {
1954 "VMware Virtual Serial Port Proxy",
1958 dissect_vmware_subopt
1961 static const tn_opt telnet_opt_unknown
= {
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
;
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
;
1990 tvbuff_t
*unescaped_tvb
;
1995 * As data with value iac (0xff) is possible, this value must be escaped
1996 * with iac (rfc 854).
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
);
2007 /* Search for an unescaped IAC. */
2008 cur_offset
= offset
;
2009 len
= tvb_reported_length_remaining(tvb
, offset
);
2011 iac_offset
= tvb_find_uint8(tvb
, cur_offset
, len
, TN_IAC
);
2013 if (iac_offset
== -1) {
2014 /* None found - run to the end of the packet. */
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
;
2023 * We saw an escaped IAC, so we have to move ahead to the
2027 cur_offset
= iac_offset
+ 2;
2032 } while (!iac_found
);
2034 subneg_len
= offset
- start_offset
;
2036 start_offset
+= 3; /* skip IAC, SB, and option code */
2039 if (subneg_len
> 0) {
2041 /* Now dissect the suboption parameters. */
2042 if (opt
->dissect
!= NULL
) {
2044 switch (opt
->len_type
) {
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");
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
);
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
);
2068 /* We have a dissector for this suboption's parameters; call it. */
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
);
2074 (*opt
->dissect
)(pinfo
, opt
->name
, tvb
, start_offset
, subneg_len
, option_tree
, option_item
);
2077 /* We don't have a dissector for them; just show them as data. */
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
);
2083 proto_tree_add_item(option_tree
, hf_telnet_option_data
, tvb
, start_offset
, subneg_len
, ENC_NA
);
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
)
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
);
2106 (*optname
) = wmem_strdup_printf(pinfo
->pool
, "%s %s", type
, opt
->name
);
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
);
2127 telnet_suboption_name(cmd_tree
, pinfo
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Will");
2131 telnet_suboption_name(cmd_tree
, pinfo
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Won't");
2135 telnet_suboption_name(cmd_tree
, pinfo
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Do");
2139 telnet_suboption_name(cmd_tree
, pinfo
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Don't");
2143 telnet_suboption_name(cmd_tree
, pinfo
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Suboption");
2147 optname
= val_to_str_const(optcode
, cmd_vals
, "<unknown option>");
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
);
2166 telnet_add_text(proto_tree
*tree
, tvbuff_t
*tvb
, int offset
, int len
)
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
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
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 */
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.
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
))
2234 len
= tvb_reported_length_remaining(tvb
, iac_offset
);
2240 dissect_telnet(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
2242 proto_tree
*telnet_tree
, *ti
;
2246 unsigned is_tn3270
= 0;
2247 unsigned is_tn5250
= 0;
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
;
2274 add_telnet_data_bytes_str(pinfo
, &num_info_items
, data_len
);
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
);
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
);
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.
2301 add_telnet_data_bytes_str(pinfo
, &num_info_items
, len
);
2302 telnet_add_text(telnet_tree
, tvb
, offset
, len
);
2307 return tvb_captured_length(tvb
);
2311 proto_register_telnet(void)
2313 static hf_register_info hf
[] = {
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
}
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
}
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
[] = {
2560 &ett_htstops_subopt
,
2563 &ett_vtstops_subopt
,
2567 &ett_bytemacro_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
,
2580 &ett_linemode_subopt
,
2581 &ett_xdpyloc_subopt
,
2586 &ett_tn3270e_subopt
,
2588 &ett_charset_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
);
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
2639 * indent-tabs-mode: nil
2642 * ex: set shiftwidth=2 tabstop=8 expandtab:
2643 * :indentSize=2:tabSize=8:noTabs=true: