2 * Routines for Telnet packet dissection; see RFC 854 and RFC 855
3 * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 /* Telnet authentication options as per RFC2941
26 * Kerberos v5 telnet authentication as per RFC2942
35 #include <epan/packet.h>
36 #include <epan/expert.h>
37 #include <epan/wmem/wmem.h>
38 #include <epan/asn1.h>
39 #include "packet-kerberos.h"
40 #include "packet-tn3270.h"
41 #include "packet-tn5250.h"
43 static int proto_telnet
= -1;
44 static int hf_telnet_cmd
= -1;
45 static int hf_telnet_subcmd
= -1;
46 static int hf_telnet_auth_cmd
= -1;
47 static int hf_telnet_auth_name
= -1;
48 static int hf_telnet_auth_type
= -1;
49 static int hf_telnet_auth_mod_who
= -1;
50 static int hf_telnet_auth_mod_how
= -1;
51 static int hf_telnet_auth_mod_cred_fwd
= -1;
52 static int hf_telnet_auth_mod_enc
= -1;
53 static int hf_telnet_auth_krb5_type
= -1;
55 static int hf_telnet_string_subopt_value
= -1;
56 static int hf_telnet_naws_subopt_width
= -1;
57 static int hf_telnet_naws_subopt_height
= -1;
58 static int hf_telnet_outmark_subopt_cmd
= -1;
59 static int hf_telnet_outmark_subopt_banner
= -1;
60 static int hf_telnet_comport_subopt_signature
= -1;
61 static int hf_telnet_comport_subopt_baud_rate
= -1;
62 static int hf_telnet_comport_subopt_data_size
= -1;
63 static int hf_telnet_comport_subopt_parity
= -1;
64 static int hf_telnet_comport_subopt_stop
= -1;
65 static int hf_telnet_comport_subopt_control
= -1;
66 static int hf_telnet_comport_subopt_purge
= -1;
67 static int hf_telnet_rfc_subopt_cmd
= -1;
69 static int hf_telnet_enc_cmd
= -1;
70 static int hf_telnet_enc_type
= -1;
72 static int hf_telnet_data
= -1;
74 static int hf_tn3270_subopt
= -1;
75 static int hf_tn3270_connect
= -1;
76 static int hf_tn3270_is
= -1;
77 static int hf_tn3270_request_string
= -1;
78 static int hf_tn3270_reason
= -1;
79 static int hf_tn3270_request
= -1;
80 static int hf_tn3270_regime_subopt_value
= -1;
82 static gint ett_telnet
= -1;
83 static gint ett_telnet_cmd
= -1;
84 static gint ett_telnet_subopt
= -1;
85 static gint ett_status_subopt
= -1;
86 static gint ett_rcte_subopt
= -1;
87 static gint ett_olw_subopt
= -1;
88 static gint ett_ops_subopt
= -1;
89 static gint ett_crdisp_subopt
= -1;
90 static gint ett_htstops_subopt
= -1;
91 static gint ett_htdisp_subopt
= -1;
92 static gint ett_ffdisp_subopt
= -1;
93 static gint ett_vtstops_subopt
= -1;
94 static gint ett_vtdisp_subopt
= -1;
95 static gint ett_lfdisp_subopt
= -1;
96 static gint ett_extasc_subopt
= -1;
97 static gint ett_bytemacro_subopt
= -1;
98 static gint ett_det_subopt
= -1;
99 static gint ett_supdupout_subopt
= -1;
100 static gint ett_sendloc_subopt
= -1;
101 static gint ett_termtype_subopt
= -1;
102 static gint ett_tacacsui_subopt
= -1;
103 static gint ett_outmark_subopt
= -1;
104 static gint ett_tlocnum_subopt
= -1;
105 static gint ett_tn3270reg_subopt
= -1;
106 static gint ett_x3pad_subopt
= -1;
107 static gint ett_naws_subopt
= -1;
108 static gint ett_tspeed_subopt
= -1;
109 static gint ett_rfc_subopt
= -1;
110 static gint ett_linemode_subopt
= -1;
111 static gint ett_xdpyloc_subopt
= -1;
112 static gint ett_env_subopt
= -1;
113 static gint ett_auth_subopt
= -1;
114 static gint ett_enc_subopt
= -1;
115 static gint ett_newenv_subopt
= -1;
116 static gint ett_tn3270e_subopt
= -1;
117 static gint ett_xauth_subopt
= -1;
118 static gint ett_charset_subopt
= -1;
119 static gint ett_rsp_subopt
= -1;
120 static gint ett_comport_subopt
= -1;
122 static expert_field ei_telnet_suboption_length
= EI_INIT
;
123 static expert_field ei_telnet_invalid_subcommand
= EI_INIT
;
124 static expert_field ei_telnet_invalid_linestate
= EI_INIT
;
125 static expert_field ei_telnet_invalid_stop
= EI_INIT
;
126 static expert_field ei_telnet_enc_cmd_unknown
= EI_INIT
;
127 static expert_field ei_telnet_invalid_data_size
= EI_INIT
;
128 static expert_field ei_telnet_invalid_modemstate
= EI_INIT
;
129 static expert_field ei_telnet_invalid_parity
= EI_INIT
;
130 static expert_field ei_telnet_kerberos_blob_too_long
= EI_INIT
;
131 static expert_field ei_telnet_invalid_purge
= EI_INIT
;
132 static expert_field ei_telnet_invalid_baud_rate
= EI_INIT
;
133 static expert_field ei_telnet_invalid_control
= EI_INIT
;
135 static dissector_handle_t telnet_handle
;
137 static dissector_handle_t tn3270_handle
;
138 static dissector_handle_t tn5250_handle
;
140 /* Some defines for Telnet */
142 #define TCP_PORT_TELNET 23
166 static const value_string cmd_vals
[] = {
167 { TN_EOF
, "End of File" },
168 { TN_SUSP
, "Suspend Current Process" },
169 { TN_ABORT
, "Abort Process" },
170 { TN_EOR
, "End of Record" },
171 { TN_SE
, "Suboption End" },
172 { TN_NOP
, "No Operation" },
173 { TN_DM
, "Data Mark" },
175 { TN_IP
, "Interrupt Process" },
176 { TN_AO
, "Abort Output" },
177 { TN_AYT
, "Are You There?" },
178 { TN_EC
, "Escape Character" },
179 { TN_EL
, "Erase Line" },
180 { TN_GA
, "Go Ahead" },
181 { TN_DONT
, "Don't" },
183 { TN_WONT
, "Won't" },
185 { TN_SB
, "Suboption" },
190 NO_LENGTH
, /* option has no data, hence no length */
191 FIXED_LENGTH
, /* option always has the same length */
192 VARIABLE_LENGTH
/* option is variable-length - optlen is minimum */
195 /* Member of table of IP or TCP options. */
196 typedef struct tn_opt
{
197 const char *name
; /* name of option */
198 gint
*subtree_index
; /* pointer to subtree index for option */
199 tn_opt_len_type len_type
; /* type of option length field */
200 int optlen
; /* value length should be (minimum if VARIABLE) */
201 void (*dissect
)(packet_info
*pinfo
, const char *, tvbuff_t
*, int, int, proto_tree
*, proto_item
*);
202 /* routine to dissect option */
206 check_tn3270_model(packet_info
*pinfo _U_
, const char *terminaltype
)
211 if ((strcmp(terminaltype
,"IBM-3278-2-E") == 0) || (strcmp(terminaltype
,"IBM-3278-2") == 0) ||
212 (strcmp(terminaltype
,"IBM-3278-3") == 0) || (strcmp(terminaltype
,"IBM-3278-4") == 0) ||
213 (strcmp(terminaltype
,"IBM-3278-5") == 0) || (strcmp(terminaltype
,"IBM-3277-2") == 0) ||
214 (strcmp(terminaltype
,"IBM-3279-3") == 0) || (strcmp(terminaltype
,"IBM-3279-4") == 0) ||
215 (strcmp(terminaltype
,"IBM-3279-2-E") == 0) || (strcmp(terminaltype
,"IBM-3279-2") == 0) ||
216 (strcmp(terminaltype
,"IBM-3279-4-E") == 0)) {
217 str_model
[0] = terminaltype
[9];
219 model
= atoi(str_model
);
220 add_tn3270_conversation(pinfo
, 0, model
);
225 check_for_tn3270(packet_info
*pinfo _U_
, const char *optname
, const char *terminaltype
)
227 if (strcmp(optname
,"Terminal Type") != 0) {
230 check_tn3270_model(pinfo
, terminaltype
);
232 if ((strcmp(terminaltype
,"IBM-5555-C01") == 0) || /* 24 x 80 Double-Byte Character Set color display */
233 (strcmp(terminaltype
,"IBM-5555-B01") == 0) || /* 24 x 80 Double-Byte Character Set (DBCS)*/
234 (strcmp(terminaltype
,"IBM-3477-FC") == 0) || /* 27 x 132 color display*/
235 (strcmp(terminaltype
,"IBM-3477-FG") == 0) || /* 27 x 132 monochrome display*/
236 (strcmp(terminaltype
,"IBM-3180-2") == 0) || /* 27 x 132 monochrome display*/
237 (strcmp(terminaltype
,"IBM-3179-2") == 0) || /* 24 x 80 color display*/
238 (strcmp(terminaltype
,"IBM-3196-A1") == 0) || /* 24 x 80 monochrome display*/
239 (strcmp(terminaltype
,"IBM-5292-2") == 0) || /* 24 x 80 color display*/
240 (strcmp(terminaltype
,"IBM-5291-1") == 0) || /* 24 x 80 monochrome display*/
241 (strcmp(terminaltype
,"IBM-5251-11") == 0)) /* 24 x 80 monochrome display*/
242 add_tn5250_conversation(pinfo
, 0);
246 dissect_string_subopt(packet_info
*pinfo
, const char *optname
, tvbuff_t
*tvb
, int offset
, int len
,
247 proto_tree
*tree
, proto_item
*item
)
251 cmd
= tvb_get_guint8(tvb
, offset
);
255 proto_tree_add_text(tree
, tvb
, offset
, 1, "Here's my %s", optname
);
259 proto_tree_add_item(tree
, hf_telnet_string_subopt_value
, tvb
, offset
, len
, ENC_NA
|ENC_ASCII
);
261 check_for_tn3270(pinfo
, optname
, tvb_format_text(tvb
, offset
, len
));
265 proto_tree_add_text(tree
, tvb
, offset
, 1, "Send your %s", optname
);
269 proto_tree_add_text(tree
, tvb
, offset
, len
, "Extra data");
273 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_subcommand
, "Invalid %s subcommand %u", optname
, cmd
);
278 proto_tree_add_text(tree
, tvb
, offset
, len
, "Subcommand data");
284 dissect_tn3270_regime_subopt(packet_info
*pinfo
, const char *optname _U_
, tvbuff_t
*tvb
, int offset
,
285 int len
, proto_tree
*tree
, proto_item
*item
)
287 #define TN3270_REGIME_ARE 0x01
288 #define TN3270_REGIME_IS 0x00
293 cmd
= tvb_get_guint8(tvb
, offset
);
295 case TN3270_REGIME_ARE
:
296 case TN3270_REGIME_IS
:
297 if (cmd
== TN3270_REGIME_ARE
) {
298 proto_tree_add_text(tree
, tvb
, offset
, 1, "ARE");
299 add_tn3270_conversation(pinfo
, 0, 0);
301 proto_tree_add_text(tree
, tvb
, offset
, 1, "IS");
303 proto_tree_add_item(tree
, hf_tn3270_regime_subopt_value
, tvb
, offset
+ 1, len
- 1, ENC_NA
|ENC_ASCII
);
307 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_subcommand
, "Bogus value: %u", cmd
);
316 #define TN3270_ASSOCIATE 0x00
317 #define TN3270_CONNECT 0x01
318 #define TN3270_DEVICE_TYPE 0x02
319 #define TN3270_FUNCTIONS 0x03
320 #define TN3270_IS 0x04
321 #define TN3270_REASON 0x05
322 #define TN3270_REJECT 0x06
323 #define TN3270_REQUEST 0x07
324 #define TN3270_SEND 0x08
326 #define TN3270_CONN_PARTNER 0x00
327 #define TN3270_DEVICE_IN_USE 0x01
328 #define TN3270_INV_ASSOCIATE 0x02
329 #define TN3270_INV_DEVICE_NAME 0x03
330 #define TN3270_INV_DEVICE_TYPE 0x04
331 #define TN3270_TYPE_NAME_ERROR 0x05
332 #define TN3270_UNKNOWN_ERROR 0x06
333 #define TN3270_UNSUPPORTED_REQ 0x07
335 #define TN3270_BIND_IMAGE 0x00
336 #define TN3270_DATA_STREAM_CTL 0x01
337 #define TN3270_RESPONSES 0x02
338 #define TN3270_SCS_CTL_CODES 0x03
339 #define TN3270_SYSREQ 0x04
341 static const value_string tn3270_subopt_vals
[] = {
342 { TN3270_ASSOCIATE
, "ASSOCIATE" },
343 { TN3270_CONNECT
, "CONNECT" },
344 { TN3270_DEVICE_TYPE
, "DEVICE-TYPE" },
345 { TN3270_FUNCTIONS
, "FUNCTIONS" },
347 { TN3270_REASON
, "REASON" },
348 { TN3270_REJECT
, "REJECT" },
349 { TN3270_REQUEST
, "REQUEST" },
350 { TN3270_SEND
, "SEND" },
354 static const value_string tn3270_reason_vals
[] = {
355 { TN3270_CONN_PARTNER
, "CONN-PARTNER" },
356 { TN3270_DEVICE_IN_USE
, "DEVICE-IN-USE" },
357 { TN3270_INV_ASSOCIATE
, "INV-ASSOCIATE" },
358 { TN3270_INV_DEVICE_NAME
, "INV-DEVICE-NAME" },
359 { TN3270_INV_DEVICE_TYPE
, "INV-DEVICE-TYPE" },
360 { TN3270_TYPE_NAME_ERROR
, "TYPE-NAME-ERROR" },
361 { TN3270_UNKNOWN_ERROR
, "UNKNOWN-ERROR" },
362 { TN3270_UNSUPPORTED_REQ
, "UNSUPPORTED-REQ" },
366 static const value_string tn3270_request_vals
[] = {
367 { TN3270_BIND_IMAGE
, "BIND-IMAGE" },
368 { TN3270_DATA_STREAM_CTL
, "DATA-STREAM-CTL" },
369 { TN3270_RESPONSES
, "RESPONSES" },
370 { TN3270_SCS_CTL_CODES
, "SCS-CTL-CODES" },
371 { TN3270_SYSREQ
, "SYSREQ" },
376 dissect_tn3270e_subopt(packet_info
*pinfo _U_
, const char *optname _U_
, tvbuff_t
*tvb
, int offset
,
377 int len
, proto_tree
*tree
, proto_item
*item _U_
)
382 int connect_offset
= 0;
387 cmd
= tvb_get_guint8(tvb
, offset
);
388 proto_tree_add_item( tree
, hf_tn3270_subopt
, tvb
, offset
, 1, ENC_NA
);
391 proto_tree_add_item( tree
, hf_tn3270_connect
, tvb
, offset
+ 1, len
, ENC_NA
|ENC_ASCII
);
396 device_type
= tvb_get_guint8(tvb
, offset
-1);
397 if (device_type
== TN3270_DEVICE_TYPE
) {
398 /* If there is a terminal type to display, then it will be followed by CONNECT */
399 connect_offset
= tvb_find_guint8(tvb
, offset
+ 1, len
, TN3270_CONNECT
);
400 if (connect_offset
!= -1) {
401 datalen
= connect_offset
- (offset
+ 1);
403 proto_tree_add_item( tree
, hf_tn3270_is
, tvb
, offset
+ 1, datalen
, ENC_NA
|ENC_ASCII
);
404 check_tn3270_model(pinfo
, tvb_format_text(tvb
, offset
+ 1, datalen
));
414 proto_tree_add_item( tree
, hf_tn3270_reason
, tvb
, offset
, 1, ENC_NA
);
417 add_tn3270_conversation(pinfo
, 1, 0);
418 device_type
= tvb_get_guint8(tvb
, offset
-1);
419 if (device_type
== TN3270_DEVICE_TYPE
) {
420 proto_tree_add_item( tree
, hf_tn3270_request_string
, tvb
, offset
+ 1, len
-1, ENC_NA
|ENC_ASCII
);
423 }else if (device_type
== TN3270_FUNCTIONS
) {
425 rsn
= tvb_get_guint8(tvb
, offset
);
426 proto_tree_add_item( tree
, hf_tn3270_request
, tvb
, offset
, 1, ENC_NA
);
427 if (try_val_to_str(rsn
, tn3270_request_vals
) == NULL
)
442 static const value_string telnet_outmark_subopt_cmd_vals
[] = {
454 dissect_outmark_subopt(packet_info
*pinfo _U_
, const char *optname _U_
, tvbuff_t
*tvb
, int offset
,
455 int len
, proto_tree
*tree
, proto_item
*item _U_
)
457 int gs_offset
, datalen
;
460 proto_tree_add_item(tree
, hf_telnet_outmark_subopt_cmd
, tvb
, offset
, 1, ENC_NA
);
466 gs_offset
= tvb_find_guint8(tvb
, offset
, len
, 29);
467 if (gs_offset
== -1) {
468 /* None found - run to the end of the packet. */
469 gs_offset
= offset
+ len
;
471 datalen
= gs_offset
- offset
;
473 proto_tree_add_item(tree
, hf_telnet_outmark_subopt_banner
, tvb
, offset
, datalen
, ENC_NA
|ENC_ASCII
);
481 dissect_htstops_subopt(packet_info
*pinfo
, const char *optname
, tvbuff_t
*tvb
, int offset
, int len
,
482 proto_tree
*tree
, proto_item
*item
)
487 cmd
= tvb_get_guint8(tvb
, offset
);
491 proto_tree_add_text(tree
, tvb
, offset
, 1, "Here's my %s", optname
);
497 proto_tree_add_text(tree
, tvb
, offset
, 1, "Send your %s", optname
);
503 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_subcommand
, "Invalid %s subcommand %u", optname
, cmd
);
507 proto_tree_add_text(tree
, tvb
, offset
, len
, "Subcommand data");
512 tabval
= tvb_get_guint8(tvb
, offset
);
516 proto_tree_add_text(tree
, tvb
, offset
, 1,
517 "Sender wants to handle tab stops");
521 proto_tree_add_text(tree
, tvb
, offset
, 1,
522 "Sender wants receiver to handle tab stop at %u",
530 proto_tree_add_text(tree
, tvb
, offset
, 1,
531 "Invalid value: %u", tabval
);
535 proto_tree_add_text(tree
, tvb
, offset
, 1,
536 "Sender wants receiver to handle tab stops");
545 dissect_naws_subopt(packet_info
*pinfo _U_
, const char *optname _U_
, tvbuff_t
*tvb
, int offset
,
546 int len _U_
, proto_tree
*tree
, proto_item
*item _U_
)
548 proto_tree_add_item(tree
, hf_telnet_naws_subopt_width
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
550 proto_tree_add_item(tree
, hf_telnet_naws_subopt_height
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
553 /* BEGIN RFC-2217 (COM Port Control) Definitions */
555 #define TNCOMPORT_SIGNATURE 0
556 #define TNCOMPORT_SETBAUDRATE 1
557 #define TNCOMPORT_SETDATASIZE 2
558 #define TNCOMPORT_SETPARITY 3
559 #define TNCOMPORT_SETSTOPSIZE 4
560 #define TNCOMPORT_SETCONTROL 5
561 #define TNCOMPORT_NOTIFYLINESTATE 6
562 #define TNCOMPORT_NOTIFYMODEMSTATE 7
563 #define TNCOMPORT_FLOWCONTROLSUSPEND 8
564 #define TNCOMPORT_FLOWCONTROLRESUME 9
565 #define TNCOMPORT_SETLINESTATEMASK 10
566 #define TNCOMPORT_SETMODEMSTATEMASK 11
567 #define TNCOMPORT_PURGEDATA 12
569 /* END RFC-2217 (COM Port Control) Definitions */
572 dissect_comport_subopt(packet_info
*pinfo
, const char *optname
, tvbuff_t
*tvb
, int offset
, int len
,
573 proto_tree
*tree
, proto_item
*item
)
575 static const char *datasizes
[] = {
586 static const char *parities
[] = {
594 static const char *stops
[] = {
600 static const char *control
[] = {
601 "Output Flow Control Request",
603 "Output Flow: XON/XOFF",
604 "Output Flow: CTS/RTS",
614 "Input Flow Control Request",
616 "Input Flow: XON/XOFF",
617 "Input Flow: CTS/RTS",
622 static const char *linestate_bits
[] = {
628 "Transfer Holding Register Empty",
629 "Transfer Shift Register Empty",
632 static const char *modemstate_bits
[] = {
642 static const char *purges
[] = {
653 cmd
= tvb_get_guint8(tvb
, offset
);
654 isservercmd
= cmd
> 99;
655 cmd
= (isservercmd
) ? (cmd
- 100) : cmd
;
656 source
= (isservercmd
) ? "Server" : "Client";
658 case TNCOMPORT_SIGNATURE
:
661 proto_tree_add_text(tree
, tvb
, offset
, 1, "%s Requests Signature",source
);
663 guint8
*sig
= tvb_get_string(wmem_packet_scope(), tvb
, offset
+ 1, len
);
664 proto_tree_add_string_format_value(tree
, hf_telnet_comport_subopt_signature
, tvb
, offset
, 1 + len
, sig
,
665 "%s Signature: %s",source
, sig
);
669 case TNCOMPORT_SETBAUDRATE
:
672 guint32 baud
= tvb_get_ntohl(tvb
, offset
+1);
674 proto_tree_add_uint_format_value(tree
, hf_telnet_comport_subopt_baud_rate
, tvb
, offset
, 5, 0, "%s Requests Baud Rate",source
);
676 proto_tree_add_uint_format_value(tree
, hf_telnet_comport_subopt_baud_rate
, tvb
, offset
, 5, baud
, "%s Baud Rate: %d",source
,baud
);
679 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_baud_rate
, "%s <Invalid Baud Rate Packet>", source
);
683 case TNCOMPORT_SETDATASIZE
:
686 guint8 datasize
= tvb_get_guint8(tvb
, offset
+1);
687 const char *ds
= (datasize
> 8) ? "<invalid>" : datasizes
[datasize
];
688 proto_tree_add_uint_format_value(tree
, hf_telnet_comport_subopt_data_size
, tvb
, offset
, 2, datasize
,
689 "%s Data Size: %s",source
,ds
);
691 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_data_size
, "%s <Invalid Data Size Packet>", source
);
695 case TNCOMPORT_SETPARITY
:
698 guint8 parity
= tvb_get_guint8(tvb
, offset
+1);
699 const char *pr
= (parity
> 5) ? "<invalid>" : parities
[parity
];
700 proto_tree_add_uint_format_value(tree
, hf_telnet_comport_subopt_parity
, tvb
, offset
, 2, parity
,
701 "%s Parity: %s",source
,pr
);
703 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_parity
, "%s <Invalid Parity Packet>", source
);
706 case TNCOMPORT_SETSTOPSIZE
:
709 guint8 stop
= tvb_get_guint8(tvb
, offset
+1);
710 const char *st
= (stop
> 3) ? "<invalid>" : stops
[stop
];
711 proto_tree_add_uint_format_value(tree
, hf_telnet_comport_subopt_stop
, tvb
, offset
, 2, stop
,
712 "%s Stop: %s",source
,st
);
714 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_stop
, "%s <Invalid Stop Packet>", source
);
718 case TNCOMPORT_SETCONTROL
:
721 guint8 crt
= tvb_get_guint8(tvb
, offset
+1);
722 const char *c
= (crt
> 19) ? "Control: <invalid>" : control
[crt
];
723 proto_tree_add_uint_format_value(tree
, hf_telnet_comport_subopt_control
, tvb
, offset
, 2, crt
,
724 "%s Stop: %s",source
,c
);
726 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_control
, "%s <Invalid Control Packet>", source
);
730 case TNCOMPORT_SETLINESTATEMASK
:
731 case TNCOMPORT_NOTIFYLINESTATE
:
734 const char *print_pattern
= (cmd
== TNCOMPORT_SETLINESTATEMASK
) ?
735 "%s Set Linestate Mask: %s" : "%s Linestate: %s";
737 guint8 ls
= tvb_get_guint8(tvb
, offset
+1);
741 for (idx
= 0; idx
< 8; idx
++) {
744 if (print_count
!= 0) {
745 g_strlcat(ls_buffer
,", ",512);
747 g_strlcat(ls_buffer
,linestate_bits
[idx
], 512);
752 proto_tree_add_text(tree
, tvb
, offset
, 2, print_pattern
, source
, ls_buffer
);
754 const char *print_pattern
= (cmd
== TNCOMPORT_SETLINESTATEMASK
) ?
755 "%s <Invalid Linestate Mask>" : "%s <Invalid Linestate Packet>";
756 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_linestate
, print_pattern
, source
);
760 case TNCOMPORT_SETMODEMSTATEMASK
:
761 case TNCOMPORT_NOTIFYMODEMSTATE
:
764 const char *print_pattern
= (cmd
== TNCOMPORT_SETMODEMSTATEMASK
) ?
765 "%s Set Modemstate Mask: %s" : "%s Modemstate: %s";
767 guint8 ms
= tvb_get_guint8(tvb
, offset
+1);
771 for (idx
= 0; idx
< 8; idx
++) {
774 if (print_count
!= 0) {
775 g_strlcat(ms_buffer
,", ",256);
777 g_strlcat(ms_buffer
,modemstate_bits
[idx
],256);
782 proto_tree_add_text(tree
, tvb
, offset
, 2, print_pattern
, source
, ms_buffer
);
784 const char *print_pattern
= (cmd
== TNCOMPORT_SETMODEMSTATEMASK
) ?
785 "%s <Invalid Modemstate Mask>" : "%s <Invalid Modemstate Packet>";
786 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_modemstate
, print_pattern
, source
);
790 case TNCOMPORT_FLOWCONTROLSUSPEND
:
792 proto_tree_add_text(tree
, tvb
, offset
, 1, "%s Flow Control Suspend",source
);
795 case TNCOMPORT_FLOWCONTROLRESUME
:
797 proto_tree_add_text(tree
, tvb
, offset
, 1, "%s Flow Control Resume",source
);
800 case TNCOMPORT_PURGEDATA
:
803 guint8 purge
= tvb_get_guint8(tvb
, offset
+1);
804 const char *p
= (purge
> 3) ? "<Purge invalid>" : purges
[purge
];
805 proto_tree_add_uint_format_value(tree
, hf_telnet_comport_subopt_purge
, tvb
, offset
, 2, purge
,
808 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_purge
, "%s <Invalid Purge Packet>", source
);
813 expert_add_info_format(pinfo
, item
, &ei_telnet_invalid_subcommand
, "Invalid %s subcommand %u", optname
, cmd
);
817 proto_tree_add_text(tree
, tvb
, offset
, len
, "Subcommand data");
823 static const value_string rfc_opt_vals
[] = {
826 { 2, "RESTART-ANY" },
827 { 3, "RESTART-XON" },
832 dissect_rfc_subopt(packet_info
*pinfo _U_
, const char *optname _U_
, tvbuff_t
*tvb
, int offset
,
833 int len _U_
, proto_tree
*tree
, proto_item
*item _U_
)
835 proto_tree_add_item(tree
, hf_telnet_rfc_subopt_cmd
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
839 #define TN_ENC_SUPPORT 1
840 #define TN_ENC_REPLY 2
841 #define TN_ENC_START 3
843 #define TN_ENC_REQUEST_START 5
844 #define TN_ENC_REQUEST_END 6
845 #define TN_ENC_ENC_KEYID 7
846 #define TN_ENC_DEC_KEYID 8
847 static const value_string enc_cmd_vals
[] = {
849 { TN_ENC_SUPPORT
, "SUPPORT" },
850 { TN_ENC_REPLY
, "REPLY" },
851 { TN_ENC_START
, "START" },
852 { TN_ENC_END
, "END" },
853 { TN_ENC_REQUEST_START
, "REQUEST-START" },
854 { TN_ENC_REQUEST_END
, "REQUEST-END" },
855 { TN_ENC_ENC_KEYID
, "ENC_KEYID" },
856 { TN_ENC_DEC_KEYID
, "DEC_KEYID" },
860 #define TN_ENCTYPE_NULL 0
861 #define TN_ENCTYPE_DES_CFB64 1
862 #define TN_ENCTYPE_DES_OFB64 2
863 #define TN_ENCTYPE_DES3_CFB64 3
864 #define TN_ENCTYPE_DES3_OFB64 4
865 #define TN_ENCTYPE_CAST5_40_CFB64 8
866 #define TN_ENCTYPE_CAST5_40_OFB64 9
867 #define TN_ENCTYPE_CAST128_CFB64 10
868 #define TN_ENCTYPE_CAST128_OFB64 11
869 static const value_string enc_type_vals
[] = {
870 { TN_ENCTYPE_NULL
, "NULL" },
871 { TN_ENCTYPE_DES_CFB64
, "DES_CFB64" },
872 { TN_ENCTYPE_DES_OFB64
, "DES_OFB64" },
873 { TN_ENCTYPE_DES3_CFB64
, "DES3_CFB64" },
874 { TN_ENCTYPE_DES3_OFB64
, "DES3_OFB64" },
875 { TN_ENCTYPE_CAST5_40_CFB64
, "CAST5_40_CFB64" },
876 { TN_ENCTYPE_CAST5_40_OFB64
, "CAST5_40_OFB64" },
877 { TN_ENCTYPE_CAST128_CFB64
, "CAST128_CFB64" },
878 { TN_ENCTYPE_CAST128_OFB64
, "CAST128_OFB64" },
885 #define TN_AC_REPLY 2
887 static const value_string auth_cmd_vals
[] = {
889 { TN_AC_SEND
, "SEND" },
890 { TN_AC_REPLY
, "REPLY" },
891 { TN_AC_NAME
, "NAME" },
903 #define TN_AT_LOKI 10
905 #define TN_AT_KEA_SJ 12
906 #define TN_AT_KEA_SJ_INTEG 13
908 #define TN_AT_NTLM 15
909 static const value_string auth_type_vals
[] = {
910 { TN_AT_NULL
, "NULL" },
911 { TN_AT_KRB4
, "Kerberos v4" },
912 { TN_AT_KRB5
, "Kerberos v5" },
913 { TN_AT_SPX
, "SPX" },
914 { TN_AT_MINK
, "MINK" },
915 { TN_AT_SRP
, "SRP" },
916 { TN_AT_RSA
, "RSA" },
917 { TN_AT_SSL
, "SSL" },
918 { TN_AT_LOKI
, "LOKI" },
919 { TN_AT_SSA
, "SSA" },
920 { TN_AT_KEA_SJ
, "KEA_SJ" },
921 { TN_AT_KEA_SJ_INTEG
, "KEA_SJ_INTEG" },
922 { TN_AT_DSS
, "DSS" },
923 { TN_AT_NTLM
, "NTLM" },
926 static const true_false_string auth_mod_cred_fwd
= {
927 "Client WILL forward auth creds",
928 "Client will NOT forward auth creds"
930 static const true_false_string auth_mod_who
= {
931 "Mask server to client",
932 "Mask client to server"
934 static const true_false_string auth_mod_how
= {
935 "MUTUAL authentication",
936 "One Way authentication"
938 #define TN_AM_OFF 0x00
939 #define TN_AM_USING_TELOPT 0x01
940 #define TN_AM_AFTER_EXCHANGE 0x02
941 #define TN_AM_RESERVED 0x04
942 static const value_string auth_mod_enc
[] = {
943 { TN_AM_OFF
, "Off" },
944 { TN_AM_USING_TELOPT
, "Telnet Options" },
945 { TN_AM_AFTER_EXCHANGE
, "After Exchange" },
946 { TN_AM_RESERVED
, "Reserved" },
949 #define TN_KRB5_TYPE_AUTH 0
950 #define TN_KRB5_TYPE_REJECT 1
951 #define TN_KRB5_TYPE_ACCEPT 2
952 #define TN_KRB5_TYPE_RESPONSE 3
953 #define TN_KRB5_TYPE_FORWARD 4
954 #define TN_KRB5_TYPE_FORWARD_ACCEPT 5
955 #define TN_KRB5_TYPE_FORWARD_REJECT 6
956 static const value_string auth_krb5_types
[] = {
957 { TN_KRB5_TYPE_AUTH
, "Auth" },
958 { TN_KRB5_TYPE_REJECT
, "Reject" },
959 { TN_KRB5_TYPE_ACCEPT
, "Accept" },
960 { TN_KRB5_TYPE_RESPONSE
, "Response" },
961 { TN_KRB5_TYPE_FORWARD
, "Forward" },
962 { TN_KRB5_TYPE_FORWARD_ACCEPT
, "Forward Accept" },
963 { TN_KRB5_TYPE_FORWARD_REJECT
, "Forward Reject" },
967 dissect_authentication_type_pair(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, proto_tree
*tree
)
971 type
=tvb_get_guint8(tvb
, offset
);
972 proto_tree_add_uint(tree
, hf_telnet_auth_type
, tvb
, offset
, 1, type
);
974 mod
=tvb_get_guint8(tvb
, offset
+1);
975 proto_tree_add_uint(tree
, hf_telnet_auth_mod_enc
, tvb
, offset
+1, 1, mod
);
976 proto_tree_add_boolean(tree
, hf_telnet_auth_mod_cred_fwd
, tvb
, offset
+1, 1, mod
);
977 proto_tree_add_boolean(tree
, hf_telnet_auth_mod_how
, tvb
, offset
+1, 1, mod
);
978 proto_tree_add_boolean(tree
, hf_telnet_auth_mod_who
, tvb
, offset
+1, 1, mod
);
981 /* no kerberos blobs are ever >10kb ? (arbitrary limit) */
982 #define MAX_KRB5_BLOB_LEN 10240
985 unescape_and_tvbuffify_telnet_option(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int len
)
993 if(len
>=MAX_KRB5_BLOB_LEN
)
996 spos
=tvb_get_ptr(tvb
, offset
, len
);
997 buf
=(guint8
*)g_malloc(len
);
1002 if((spos
[0]==0xff) && (spos
[1]==0xff)){
1009 *(dpos
++)=*(spos
++);
1012 krb5_tvb
= tvb_new_child_real_data(tvb
, buf
, len
-skip
, len
-skip
);
1013 tvb_set_free_cb(krb5_tvb
, g_free
);
1014 add_new_data_source(pinfo
, krb5_tvb
, "Unpacked Telnet Option");
1020 /* as per RFC2942 */
1022 dissect_krb5_authentication_data(packet_info
*pinfo
, tvbuff_t
*tvb
, int offset
, int len
, proto_tree
*tree
, guint8 acmd
)
1028 dissect_authentication_type_pair(pinfo
, tvb
, offset
, tree
);
1033 krb5_cmd
=tvb_get_guint8(tvb
, offset
);
1034 ti
= proto_tree_add_uint(tree
, hf_telnet_auth_krb5_type
, tvb
, offset
, 1, krb5_cmd
);
1039 /* IAC SB AUTHENTICATION IS <authentication-type-pair> AUTH <Kerberos V5 KRB_AP_REQ message> IAC SE */
1040 if((acmd
==TN_AC_IS
)&&(krb5_cmd
==TN_KRB5_TYPE_AUTH
)){
1042 krb5_tvb
=unescape_and_tvbuffify_telnet_option(pinfo
, tvb
, offset
, len
);
1044 dissect_kerberos_main(krb5_tvb
, pinfo
, tree
, FALSE
, NULL
);
1046 expert_add_info_format(pinfo
, ti
, &ei_telnet_kerberos_blob_too_long
, "Kerberos blob (too long to dissect - length %u > %u)", len
, MAX_KRB5_BLOB_LEN
);
1052 /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> ACCEPT IAC SE */
1053 /* nothing more to dissect */
1057 /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> REJECT <optional reason for rejection> IAC SE*/
1061 /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> RESPONSE <KRB_AP_REP message> IAC SE */
1062 if((acmd
==TN_AC_REPLY
)&&(krb5_cmd
==TN_KRB5_TYPE_RESPONSE
)){
1064 krb5_tvb
=unescape_and_tvbuffify_telnet_option(pinfo
, tvb
, offset
, len
);
1065 dissect_kerberos_main(krb5_tvb
, pinfo
, tree
, FALSE
, NULL
);
1070 /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD <KRB_CRED message> IAC SE */
1071 /* XXX unclear what this one looks like */
1074 /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_ACCEPT IAC SE */
1075 /* nothing more to dissect */
1079 /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_REJECT */
1080 /* nothing more to dissect */
1084 dissect_authentication_subopt(packet_info
*pinfo
, const char *optname _U_
, tvbuff_t
*tvb
, int offset
, int len
,
1085 proto_tree
*tree
, proto_item
*item _U_
)
1089 /* XXX here we should really split it up in a conversation struct keeping
1090 track of what method we actually use and not just assume it is always
1093 acmd
=tvb_get_guint8(tvb
, offset
);
1094 proto_tree_add_uint(tree
, hf_telnet_auth_cmd
, tvb
, offset
, 1, acmd
);
1101 /* XXX here we shouldnt just assume it is krb5 */
1102 dissect_krb5_authentication_data(pinfo
, tvb
, offset
, len
, tree
, acmd
);
1106 dissect_authentication_type_pair(pinfo
, tvb
, offset
, tree
);
1112 proto_tree_add_item(tree
, hf_telnet_auth_name
, tvb
, offset
, len
, ENC_ASCII
);
1117 /* This function only uses the octet in the buffer at 'offset' */
1118 static void dissect_encryption_type(tvbuff_t
*tvb
, int offset
, proto_tree
*tree
) {
1120 etype
= tvb_get_guint8(tvb
, offset
);
1121 proto_tree_add_uint(tree
, hf_telnet_enc_type
, tvb
, offset
, 1, etype
);
1125 dissect_encryption_subopt(packet_info
*pinfo
, const char *optname _U_
, tvbuff_t
*tvb
, int offset
, int len
,
1126 proto_tree
*tree
, proto_item
*item
)
1128 guint8 ecmd
, key_first_octet
;
1130 ecmd
= tvb_get_guint8(tvb
, offset
);
1131 proto_tree_add_uint(tree
, hf_telnet_enc_cmd
, tvb
, offset
, 1, ecmd
);
1139 /* encryption type, type-specific data ... */
1141 dissect_encryption_type(tvb
, offset
, tree
);
1144 proto_tree_add_text(tree
, tvb
, offset
, len
, "Type-specific data");
1148 case TN_ENC_SUPPORT
:
1149 /* list of encryption types ... */
1151 dissect_encryption_type(tvb
, offset
, tree
);
1160 key_first_octet
= tvb_get_guint8(tvb
, offset
);
1161 proto_tree_add_text(tree
, tvb
, offset
, len
, (key_first_octet
== 0) ? "Default key" : "Key ID");
1169 case TN_ENC_REQUEST_START
:
1170 /* (optional) keyid */
1172 proto_tree_add_text(tree
, tvb
, offset
, len
, "Key ID (advisory)");
1175 case TN_ENC_REQUEST_END
:
1179 case TN_ENC_ENC_KEYID
:
1180 case TN_ENC_DEC_KEYID
:
1181 /* (optional) keyid - if not supplied, there are no more known keys */
1183 proto_tree_add_text(tree
, tvb
, offset
, len
, "Key ID");
1187 expert_add_info(pinfo
, item
, &ei_telnet_enc_cmd_unknown
);
1191 static tn_opt options
[] = {
1193 "Binary Transmission", /* RFC 856 */
1194 NULL
, /* no suboption negotiation */
1200 "Echo", /* RFC 857 */
1201 NULL
, /* no suboption negotiation */
1207 "Reconnection", /* DOD Protocol Handbook */
1214 "Suppress Go Ahead", /* RFC 858 */
1215 NULL
, /* no suboption negotiation */
1221 "Approx Message Size Negotiation", /* Ethernet spec(!) */
1228 "Status", /* RFC 859 */
1232 NULL
/* XXX - fill me in */
1235 "Timing Mark", /* RFC 860 */
1236 NULL
, /* no suboption negotiation */
1242 "Remote Controlled Trans and Echo", /* RFC 726 */
1246 NULL
/* XXX - fill me in */
1249 "Output Line Width", /* DOD Protocol Handbook */
1251 VARIABLE_LENGTH
, /* XXX - fill me in */
1252 0, /* XXX - fill me in */
1253 NULL
/* XXX - fill me in */
1256 "Output Page Size", /* DOD Protocol Handbook */
1258 VARIABLE_LENGTH
, /* XXX - fill me in */
1259 0, /* XXX - fill me in */
1260 NULL
/* XXX - fill me in */
1263 "Output Carriage-Return Disposition", /* RFC 652 */
1267 NULL
/* XXX - fill me in */
1270 "Output Horizontal Tab Stops", /* RFC 653 */
1271 &ett_htstops_subopt
,
1274 dissect_htstops_subopt
1277 "Output Horizontal Tab Disposition", /* RFC 654 */
1281 NULL
/* XXX - fill me in */
1284 "Output Formfeed Disposition", /* RFC 655 */
1288 NULL
/* XXX - fill me in */
1291 "Output Vertical Tabstops", /* RFC 656 */
1292 &ett_vtstops_subopt
,
1295 NULL
/* XXX - fill me in */
1298 "Output Vertical Tab Disposition", /* RFC 657 */
1302 NULL
/* XXX - fill me in */
1305 "Output Linefeed Disposition", /* RFC 658 */
1309 NULL
/* XXX - fill me in */
1312 "Extended ASCII", /* RFC 698 */
1316 NULL
/* XXX - fill me in */
1319 "Logout", /* RFC 727 */
1320 NULL
, /* no suboption negotiation */
1326 "Byte Macro", /* RFC 735 */
1327 &ett_bytemacro_subopt
,
1330 NULL
/* XXX - fill me in */
1333 "Data Entry Terminal", /* RFC 732, RFC 1043 */
1337 NULL
/* XXX - fill me in */
1340 "SUPDUP", /* RFC 734, RFC 736 */
1341 NULL
, /* no suboption negotiation */
1347 "SUPDUP Output", /* RFC 749 */
1348 &ett_supdupout_subopt
,
1351 NULL
/* XXX - fill me in */
1354 "Send Location", /* RFC 779 */
1355 &ett_sendloc_subopt
,
1358 NULL
/* XXX - fill me in */
1361 "Terminal Type", /* RFC 1091 */
1362 &ett_termtype_subopt
,
1365 dissect_string_subopt
1368 "End of Record", /* RFC 885 */
1369 NULL
, /* no suboption negotiation */
1375 "TACACS User Identification", /* RFC 927 */
1376 &ett_tacacsui_subopt
,
1379 NULL
/* XXX - fill me in */
1382 "Output Marking", /* RFC 933 */
1383 &ett_outmark_subopt
,
1386 dissect_outmark_subopt
,
1389 "Terminal Location Number", /* RFC 946 */
1390 &ett_tlocnum_subopt
,
1393 NULL
/* XXX - fill me in */
1396 "Telnet 3270 Regime", /* RFC 1041 */
1397 &ett_tn3270reg_subopt
,
1400 dissect_tn3270_regime_subopt
1403 "X.3 PAD", /* RFC 1053 */
1407 NULL
/* XXX - fill me in */
1410 "Negotiate About Window Size", /* RFC 1073, DW183 */
1417 "Terminal Speed", /* RFC 1079 */
1421 NULL
/* XXX - fill me in */
1424 "Remote Flow Control", /* RFC 1372 */
1431 "Linemode", /* RFC 1184 */
1432 &ett_linemode_subopt
,
1435 NULL
/* XXX - fill me in */
1438 "X Display Location", /* RFC 1096 */
1439 &ett_xdpyloc_subopt
,
1442 dissect_string_subopt
1445 "Environment Option", /* RFC 1408, RFC 1571 */
1449 NULL
/* XXX - fill me in */
1452 "Authentication Option", /* RFC 2941 */
1456 dissect_authentication_subopt
1459 "Encryption Option", /* RFC 2946 */
1463 dissect_encryption_subopt
1466 "New Environment Option", /* RFC 1572 */
1470 NULL
/* XXX - fill me in */
1473 "TN3270E", /* RFC 1647 */
1474 &ett_tn3270e_subopt
,
1477 dissect_tn3270e_subopt
1480 "XAUTH", /* XAUTH */
1484 NULL
/* XXX - fill me in */
1487 "CHARSET", /* CHARSET */
1488 &ett_charset_subopt
,
1491 NULL
/* XXX - fill me in */
1494 "Remote Serial Port", /* Remote Serial Port */
1498 NULL
/* XXX - fill me in */
1501 "COM Port Control", /* RFC 2217 */
1502 &ett_comport_subopt
,
1505 dissect_comport_subopt
1510 #define NOPTIONS array_length(options)
1513 telnet_sub_option(packet_info
*pinfo
, proto_tree
*option_tree
, proto_item
*option_item
, tvbuff_t
*tvb
, int start_offset
)
1515 int offset
= start_offset
;
1521 tvbuff_t
*unescaped_tvb
;
1522 void (*dissect
)(packet_info
*, const char *, tvbuff_t
*, int, int, proto_tree
*, proto_item
*);
1527 * As data with value iac (0xff) is possible, this value must be escaped
1528 * with iac (rfc 854).
1532 offset
+= 2; /* skip IAC and SB */
1534 /* Get the option code */
1535 opt_byte
= tvb_get_guint8(tvb
, offset
);
1536 if (opt_byte
>= NOPTIONS
) {
1537 opt
= "<unknown option>";
1540 opt
= options
[opt_byte
].name
;
1541 dissect
= options
[opt_byte
].dissect
;
1545 /* Search for an unescaped IAC. */
1546 cur_offset
= offset
;
1547 len
= tvb_length_remaining(tvb
, offset
);
1549 iac_offset
= tvb_find_guint8(tvb
, cur_offset
, len
, TN_IAC
);
1551 if (iac_offset
== -1) {
1552 /* None found - run to the end of the packet. */
1555 if (((guint
)(iac_offset
+ 1) >= len
) ||
1556 (tvb_get_guint8(tvb
, iac_offset
+ 1) != TN_IAC
)) {
1557 /* We really found a single IAC, so we're done */
1558 offset
= iac_offset
;
1561 * We saw an escaped IAC, so we have to move ahead to the
1565 cur_offset
= iac_offset
+ 2;
1570 } while (!iac_found
);
1572 subneg_len
= offset
- start_offset
;
1574 start_offset
+= 3; /* skip IAC, SB, and option code */
1577 if (subneg_len
> 0) {
1579 /* Now dissect the suboption parameters. */
1580 if (dissect
!= NULL
) {
1582 switch (options
[opt_byte
].len_type
) {
1585 /* There isn't supposed to *be* sub-option negotiation for this. */
1586 expert_add_info_format(pinfo
, option_item
, &ei_telnet_suboption_length
, "Bogus suboption data");
1590 /* Make sure the length is what it's supposed to be. */
1591 if (subneg_len
- iac_data
!= options
[opt_byte
].optlen
) {
1592 expert_add_info_format(pinfo
, option_item
, &ei_telnet_suboption_length
, "Suboption parameter length is %d, should be %d", subneg_len
, options
[opt_byte
].optlen
);
1597 case VARIABLE_LENGTH
:
1598 /* Make sure the length is greater than the minimum. */
1599 if (subneg_len
- iac_data
< options
[opt_byte
].optlen
) {
1600 expert_add_info_format(pinfo
, option_item
, &ei_telnet_suboption_length
, "Suboption parameter length is %d, should be at least %d", subneg_len
, options
[opt_byte
].optlen
);
1606 /* We have a dissector for this suboption's parameters; call it. */
1608 /* Data is escaped, we have to unescape it. */
1609 unescaped_tvb
= unescape_and_tvbuffify_telnet_option(pinfo
, tvb
, start_offset
, subneg_len
);
1610 (*dissect
)(pinfo
, opt
, unescaped_tvb
, 0, subneg_len
- iac_data
, option_tree
, option_item
);
1612 (*dissect
)(pinfo
, opt
, tvb
, start_offset
, subneg_len
, option_tree
, option_item
);
1615 /* We don't have a dissector for them; just show them as data. */
1617 /* Data is escaped, we have to unescape it. */
1618 unescaped_tvb
= unescape_and_tvbuffify_telnet_option(pinfo
, tvb
, start_offset
, subneg_len
);
1619 proto_tree_add_text(option_tree
, unescaped_tvb
, 0, subneg_len
- iac_data
,
1622 proto_tree_add_text(option_tree
, tvb
, start_offset
, subneg_len
,
1631 telnet_suboption_name(proto_tree
*tree
, tvbuff_t
*tvb
, int* offset
, gchar
** optname
,
1632 proto_tree
**opt_tree
, proto_item
**opt_item
, const char *type
)
1636 gint ett
= ett_telnet_subopt
;
1638 opt_byte
= tvb_get_guint8(tvb
, *offset
);
1639 if (opt_byte
>= NOPTIONS
) {
1640 opt
= "<unknown option>";
1643 opt
= options
[opt_byte
].name
;
1644 if (options
[opt_byte
].subtree_index
!= NULL
)
1645 ett
= *(options
[opt_byte
].subtree_index
);
1647 *opt_item
= proto_tree_add_uint_format_value(tree
, hf_telnet_subcmd
, tvb
, *offset
, 1, opt_byte
, "%s", opt
);
1648 *opt_tree
= proto_item_add_subtree(*opt_item
, ett
);
1651 (*optname
) = wmem_strdup_printf(wmem_packet_scope(), "%s %s", type
, opt
);
1655 telnet_command(packet_info
*pinfo
, proto_tree
*telnet_tree
, tvbuff_t
*tvb
, int start_offset
)
1657 int offset
= start_offset
;
1660 proto_item
*cmd_item
, *subopt_item
= NULL
;
1661 proto_tree
*cmd_tree
, *subopt_tree
= NULL
;
1663 offset
+= 1; /* skip IAC */
1664 optcode
= tvb_get_guint8(tvb
, offset
);
1666 cmd_item
= proto_tree_add_text(telnet_tree
, tvb
, start_offset
, 2, "Command header");
1667 cmd_tree
= proto_item_add_subtree(cmd_item
, ett_telnet_cmd
);
1668 proto_tree_add_item(cmd_tree
, hf_telnet_cmd
, tvb
, offset
, 1, ENC_NA
);
1673 telnet_suboption_name(cmd_tree
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Will");
1677 telnet_suboption_name(cmd_tree
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Won't");
1681 telnet_suboption_name(cmd_tree
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Do");
1685 telnet_suboption_name(cmd_tree
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Don't");
1689 telnet_suboption_name(cmd_tree
, tvb
, &offset
, &optname
, &subopt_tree
, &subopt_item
, "Suboption");
1693 optname
= (gchar
*)val_to_str_const(optcode
, cmd_vals
, "<unknown option>");
1697 proto_item_set_text(cmd_item
, "%s", optname
);
1699 if (optcode
== TN_SB
) {
1700 offset
= telnet_sub_option(pinfo
, subopt_tree
, subopt_item
, tvb
, start_offset
);
1703 proto_item_set_len(cmd_item
, offset
-start_offset
);
1709 telnet_add_text(proto_tree
*tree
, tvbuff_t
*tvb
, int offset
, int len
)
1714 gboolean last_char_was_cr
;
1716 while (len
!= 0 && tvb_offset_exists(tvb
, offset
)) {
1718 * Find the end of the line.
1720 linelen
= tvb_find_line_end(tvb
, offset
, len
, &next_offset
, FALSE
);
1721 len
-= next_offset
- offset
; /* subtract out the line's characters */
1724 * In Telnet, CR NUL is the way you send a CR by itself in the
1725 * default ASCII mode; don't treat CR by itself as a line ending,
1726 * treat only CR NUL, CR LF, or LF by itself as a line ending.
1728 if (next_offset
== offset
+ linelen
+ 1 && len
>= 1) {
1730 * Well, we saw a one-character line ending, so either it's a CR
1731 * or an LF; we have at least two characters left, including the
1734 * If the line ending is a CR, skip all subsequent CRs; at
1735 * least one capture appeared to have multiple CRs at the end of
1738 if (tvb_get_guint8(tvb
, offset
+ linelen
) == '\r') {
1739 last_char_was_cr
= TRUE
;
1740 while (len
!= 0 && tvb_offset_exists(tvb
, next_offset
)) {
1741 c
= tvb_get_guint8(tvb
, next_offset
);
1742 next_offset
++; /* skip over that character */
1744 if (c
== '\n' || (c
== '\0' && last_char_was_cr
)) {
1746 * LF is a line ending, whether preceded by CR or not.
1747 * NUL is a line ending if preceded by CR.
1751 last_char_was_cr
= (c
== '\r');
1757 * Now compute the length of the line *including* the end-of-line
1758 * indication, if any; we display it all.
1760 linelen
= next_offset
- offset
;
1762 proto_tree_add_item(tree
, hf_telnet_data
, tvb
, offset
, linelen
, ENC_ASCII
|ENC_NA
);
1763 offset
= next_offset
;
1767 static int find_unescaped_iac(tvbuff_t
*tvb
, int offset
, int len
)
1769 int iac_offset
= offset
;
1771 /* If we find an IAC (0XFF), make sure it is not followed by another 0XFF.
1772 Such cases indicate that it is not an IAC at all */
1773 while ((iac_offset
= tvb_find_guint8(tvb
, iac_offset
, len
, TN_IAC
)) != -1 &&
1774 (tvb_get_guint8(tvb
, iac_offset
+ 1) == TN_IAC
))
1777 len
= tvb_length_remaining(tvb
, iac_offset
);
1783 dissect_telnet(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
1785 proto_tree
*telnet_tree
, *ti
;
1789 guint is_tn3270
= 0;
1790 guint is_tn5250
= 0;
1794 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TELNET");
1795 col_set_str(pinfo
->cinfo
, COL_INFO
, "Telnet Data ...");
1797 is_tn3270
= find_tn3270_conversation(pinfo
);
1798 is_tn5250
= find_tn5250_conversation(pinfo
);
1800 ti
= proto_tree_add_item(tree
, proto_telnet
, tvb
, offset
, -1, ENC_NA
);
1801 telnet_tree
= proto_item_add_subtree(ti
, ett_telnet
);
1804 * Scan through the buffer looking for an IAC byte.
1806 while ((len
= tvb_length_remaining(tvb
, offset
)) > 0) {
1807 iac_offset
= find_unescaped_iac(tvb
, offset
, len
);
1808 if (iac_offset
!= -1) {
1810 * We found an IAC byte.
1811 * If there's any data before it, add that data to the
1812 * tree, a line at a time.
1814 data_len
= iac_offset
- offset
;
1817 next_tvb
= tvb_new_subset(tvb
, offset
, data_len
, data_len
);
1818 call_dissector(tn3270_handle
, next_tvb
, pinfo
, telnet_tree
);
1819 } else if (is_tn5250
) {
1820 next_tvb
= tvb_new_subset(tvb
, offset
, data_len
, data_len
);
1821 call_dissector(tn5250_handle
, next_tvb
, pinfo
, telnet_tree
);
1823 telnet_add_text(telnet_tree
, tvb
, offset
, data_len
);
1826 * Now interpret the command.
1828 offset
= telnet_command(pinfo
, telnet_tree
, tvb
, iac_offset
);
1830 /* get more data if tn3270 */
1831 if (is_tn3270
|| is_tn5250
) {
1832 pinfo
->desegment_offset
= offset
;
1833 pinfo
->desegment_len
= DESEGMENT_ONE_MORE_SEGMENT
;
1837 * We found no IAC byte, so what remains in the buffer
1838 * is the last of the data in the packet.
1839 * Add it to the tree, a line at a time, and then quit.
1841 telnet_add_text(telnet_tree
, tvb
, offset
, len
);
1848 proto_register_telnet(void)
1850 static hf_register_info hf
[] = {
1852 { "Command", "telnet.cmd", FT_UINT8
, BASE_DEC
,
1853 VALS(cmd_vals
), 0, NULL
, HFILL
}
1855 { &hf_telnet_subcmd
,
1856 { "Subcommand", "telnet.subcmd", FT_UINT8
, BASE_DEC
,
1857 NULL
, 0, NULL
, HFILL
}
1859 { &hf_telnet_auth_name
,
1860 { "Name", "telnet.auth.name", FT_STRING
, BASE_NONE
,
1861 NULL
, 0, "Name of user being authenticated", HFILL
}
1863 { &hf_telnet_auth_cmd
,
1864 { "Auth Cmd", "telnet.auth.cmd", FT_UINT8
, BASE_DEC
,
1865 VALS(auth_cmd_vals
), 0, "Authentication Command", HFILL
}
1867 { &hf_telnet_auth_type
,
1868 { "Auth Type", "telnet.auth.type", FT_UINT8
, BASE_DEC
,
1869 VALS(auth_type_vals
), 0, "Authentication Type", HFILL
}
1871 { &hf_telnet_auth_mod_cred_fwd
,
1872 { "Cred Fwd", "telnet.auth.mod.cred_fwd", FT_BOOLEAN
, 8,
1873 TFS(&auth_mod_cred_fwd
), 0x08, "Modifier: Whether client will forward creds or not", HFILL
}
1875 { &hf_telnet_auth_mod_who
,
1876 { "Who", "telnet.auth.mod.who", FT_BOOLEAN
, 8,
1877 TFS(&auth_mod_who
), 0x01, "Modifier: Who to mask", HFILL
}
1879 { &hf_telnet_auth_mod_how
,
1880 { "How", "telnet.auth.mod.how", FT_BOOLEAN
, 8,
1881 TFS(&auth_mod_how
), 0x02, "Modifier: How to mask", HFILL
}
1883 { &hf_telnet_auth_mod_enc
,
1884 { "Encrypt", "telnet.auth.mod.enc", FT_UINT8
, BASE_DEC
,
1885 VALS(auth_mod_enc
), 0x14, "Modifier: How to enable Encryption", HFILL
}
1887 { &hf_telnet_auth_krb5_type
,
1888 { "Command", "telnet.auth.krb5.cmd", FT_UINT8
, BASE_DEC
,
1889 VALS(auth_krb5_types
), 0, "Krb5 Authentication sub-command", HFILL
}
1891 { &hf_telnet_string_subopt_value
,
1892 { "Value", "telnet.string_subopt.value", FT_STRING
, BASE_NONE
,
1893 NULL
, 0, NULL
, HFILL
}
1895 { &hf_telnet_naws_subopt_width
,
1896 { "Width", "telnet.naws_subopt.width", FT_UINT16
, BASE_DEC
,
1897 NULL
, 0, NULL
, HFILL
}
1899 { &hf_telnet_naws_subopt_height
,
1900 { "Height", "telnet.naws_subopt.height", FT_UINT16
, BASE_DEC
,
1901 NULL
, 0, NULL
, HFILL
}
1903 { &hf_telnet_outmark_subopt_cmd
,
1904 { "Command", "telnet.outmark_subopt.cmd", FT_UINT8
, BASE_DEC
,
1905 VALS(telnet_outmark_subopt_cmd_vals
), 0, NULL
, HFILL
}
1907 { &hf_telnet_outmark_subopt_banner
,
1908 { "Banner", "telnet.outmark_subopt.banner", FT_STRING
, BASE_NONE
,
1909 NULL
, 0, NULL
, HFILL
}
1911 { &hf_telnet_comport_subopt_signature
,
1912 { "Signature", "telnet.comport_subopt.signature", FT_STRING
, BASE_NONE
,
1913 NULL
, 0, NULL
, HFILL
}
1915 { &hf_telnet_comport_subopt_baud_rate
,
1916 { "Baud Rate", "telnet.comport_subopt.baud_rate", FT_UINT32
, BASE_DEC
,
1917 NULL
, 0, NULL
, HFILL
}
1919 { &hf_telnet_comport_subopt_data_size
,
1920 { "Data Size", "telnet.comport_subopt.data_size", FT_UINT8
, BASE_DEC
,
1921 NULL
, 0, NULL
, HFILL
}
1923 { &hf_telnet_comport_subopt_parity
,
1924 { "Parity", "telnet.comport_subopt.parity", FT_UINT8
, BASE_DEC
,
1925 NULL
, 0, NULL
, HFILL
}
1927 { &hf_telnet_comport_subopt_stop
,
1928 { "Stop Bits", "telnet.comport_subopt.stop", FT_UINT8
, BASE_DEC
,
1929 NULL
, 0, NULL
, HFILL
}
1931 { &hf_telnet_comport_subopt_control
,
1932 { "Control", "telnet.comport_subopt.control", FT_UINT8
, BASE_DEC
,
1933 NULL
, 0, NULL
, HFILL
}
1935 { &hf_telnet_comport_subopt_purge
,
1936 { "Purge", "telnet.comport_subopt.purge", FT_UINT8
, BASE_DEC
,
1937 NULL
, 0, NULL
, HFILL
}
1939 { &hf_telnet_rfc_subopt_cmd
,
1940 { "Command", "telnet.rfc_subopt.cmd", FT_UINT8
, BASE_DEC
,
1941 VALS(rfc_opt_vals
), 0, NULL
, HFILL
}
1943 { &hf_telnet_enc_cmd
,
1944 { "Enc Cmd", "telnet.enc.cmd", FT_UINT8
, BASE_DEC
,
1945 VALS(enc_cmd_vals
), 0, "Encryption command", HFILL
}
1947 { &hf_telnet_enc_type
,
1948 { "Enc Type", "telnet.enc.type", FT_UINT8
, BASE_DEC
,
1949 VALS(enc_type_vals
), 0, "Encryption type", HFILL
}
1952 { "Data", "telnet.data", FT_STRING
, BASE_NONE
,
1953 NULL
, 0, NULL
, HFILL
}
1955 { &hf_tn3270_subopt
,
1956 { "Suboption", "telnet.tn3270.subopt", FT_UINT8
, BASE_DEC
,
1957 VALS(tn3270_subopt_vals
), 0, NULL
, HFILL
}
1959 { &hf_tn3270_connect
,
1960 { "Connect", "telnet.tn3270.connect", FT_STRING
, BASE_NONE
,
1961 NULL
, 0, NULL
, HFILL
}
1964 { "Is", "telnet.tn3270.is", FT_STRING
, BASE_NONE
,
1965 NULL
, 0, NULL
, HFILL
}
1967 { &hf_tn3270_request_string
,
1968 { "Request", "telnet.tn3270.request_string", FT_STRING
, BASE_NONE
,
1969 NULL
, 0, NULL
, HFILL
}
1971 { &hf_tn3270_reason
,
1972 { "Reason", "telnet.tn3270.reason", FT_UINT8
, BASE_DEC
,
1973 VALS(tn3270_reason_vals
), 0, NULL
, HFILL
}
1975 { &hf_tn3270_request
,
1976 { "Request", "telnet.tn3270.request", FT_UINT8
, BASE_DEC
,
1977 VALS(tn3270_request_vals
), 0, NULL
, HFILL
}
1979 { &hf_tn3270_regime_subopt_value
,
1980 { "Value", "telnet.tn3270.regime_subopt.value", FT_STRING
, BASE_NONE
,
1981 NULL
, 0, NULL
, HFILL
}
1984 static gint
*ett
[] = {
1993 &ett_htstops_subopt
,
1996 &ett_vtstops_subopt
,
2000 &ett_bytemacro_subopt
,
2002 &ett_supdupout_subopt
,
2003 &ett_sendloc_subopt
,
2004 &ett_termtype_subopt
,
2005 &ett_tacacsui_subopt
,
2006 &ett_outmark_subopt
,
2007 &ett_tlocnum_subopt
,
2008 &ett_tn3270reg_subopt
,
2013 &ett_linemode_subopt
,
2014 &ett_xdpyloc_subopt
,
2019 &ett_tn3270e_subopt
,
2021 &ett_charset_subopt
,
2026 static ei_register_info ei
[] = {
2027 { &ei_telnet_invalid_subcommand
, { "telnet.invalid_subcommand", PI_PROTOCOL
, PI_WARN
, "Invalid subcommand", EXPFILL
}},
2028 { &ei_telnet_invalid_baud_rate
, { "telnet.invalid_baud_rate", PI_PROTOCOL
, PI_WARN
, "Invalid Baud Rate", EXPFILL
}},
2029 { &ei_telnet_invalid_data_size
, { "telnet.invalid_data_size", PI_PROTOCOL
, PI_WARN
, "Invalid Data Size", EXPFILL
}},
2030 { &ei_telnet_invalid_parity
, { "telnet.invalid_parity", PI_PROTOCOL
, PI_WARN
, "Invalid Parity Packet", EXPFILL
}},
2031 { &ei_telnet_invalid_stop
, { "telnet.invalid_stop", PI_PROTOCOL
, PI_WARN
, "Invalid Stop Packet", EXPFILL
}},
2032 { &ei_telnet_invalid_control
, { "telnet.invalid_control", PI_PROTOCOL
, PI_WARN
, "Invalid Control Packet", EXPFILL
}},
2033 { &ei_telnet_invalid_linestate
, { "telnet.invalid_linestate", PI_PROTOCOL
, PI_WARN
, "Invalid linestate", EXPFILL
}},
2034 { &ei_telnet_invalid_modemstate
, { "telnet.invalid_modemstate", PI_PROTOCOL
, PI_WARN
, "Invalid Modemstate", EXPFILL
}},
2035 { &ei_telnet_invalid_purge
, { "telnet.invalid_purge", PI_PROTOCOL
, PI_WARN
, "Invalid Purge Packet", EXPFILL
}},
2036 { &ei_telnet_kerberos_blob_too_long
, { "telnet.kerberos_blob_too_long", PI_PROTOCOL
, PI_NOTE
, "Kerberos blob too long to dissect", EXPFILL
}},
2037 { &ei_telnet_enc_cmd_unknown
, { "telnet.enc.cmd.unknown", PI_PROTOCOL
, PI_WARN
, "Unknown encryption command", EXPFILL
}},
2038 { &ei_telnet_suboption_length
, { "telnet.suboption_length.invalid", PI_PROTOCOL
, PI_WARN
, "Bogus suboption data", EXPFILL
}},
2041 expert_module_t
* expert_telnet
;
2043 proto_telnet
= proto_register_protocol("Telnet", "TELNET", "telnet");
2044 proto_register_field_array(proto_telnet
, hf
, array_length(hf
));
2045 proto_register_subtree_array(ett
, array_length(ett
));
2047 expert_telnet
= expert_register_protocol(proto_telnet
);
2048 expert_register_field_array(expert_telnet
, ei
, array_length(ei
));
2050 telnet_handle
= register_dissector("telnet", dissect_telnet
, proto_telnet
);
2054 proto_reg_handoff_telnet(void)
2056 dissector_add_uint("tcp.port", TCP_PORT_TELNET
, telnet_handle
);
2057 tn3270_handle
= find_dissector("tn3270");
2058 tn5250_handle
= find_dissector("tn5250");