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 * Copied from packet-pop.c
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /* Telnet authentication options as per RFC2941
28 * Kerberos v5 telnet authentication as per RFC2942
38 #include <epan/packet.h>
39 #include <epan/strutil.h>
40 #include <epan/emem.h>
41 #include <epan/asn1.h>
42 #include "packet-kerberos.h"
43 #include "packet-tn3270.h"
45 static int proto_telnet = -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_enc_cmd = -1;
56 static int hf_telnet_enc_type = -1;
58 static gint ett_telnet = -1;
59 static gint ett_telnet_subopt = -1;
60 static gint ett_status_subopt = -1;
61 static gint ett_rcte_subopt = -1;
62 static gint ett_olw_subopt = -1;
63 static gint ett_ops_subopt = -1;
64 static gint ett_crdisp_subopt = -1;
65 static gint ett_htstops_subopt = -1;
66 static gint ett_htdisp_subopt = -1;
67 static gint ett_ffdisp_subopt = -1;
68 static gint ett_vtstops_subopt = -1;
69 static gint ett_vtdisp_subopt = -1;
70 static gint ett_lfdisp_subopt = -1;
71 static gint ett_extasc_subopt = -1;
72 static gint ett_bytemacro_subopt = -1;
73 static gint ett_det_subopt = -1;
74 static gint ett_supdupout_subopt = -1;
75 static gint ett_sendloc_subopt = -1;
76 static gint ett_termtype_subopt = -1;
77 static gint ett_tacacsui_subopt = -1;
78 static gint ett_outmark_subopt = -1;
79 static gint ett_tlocnum_subopt = -1;
80 static gint ett_tn3270reg_subopt = -1;
81 static gint ett_x3pad_subopt = -1;
82 static gint ett_naws_subopt = -1;
83 static gint ett_tspeed_subopt = -1;
84 static gint ett_rfc_subopt = -1;
85 static gint ett_linemode_subopt = -1;
86 static gint ett_xdpyloc_subopt = -1;
87 static gint ett_env_subopt = -1;
88 static gint ett_auth_subopt = -1;
89 static gint ett_enc_subopt = -1;
90 static gint ett_newenv_subopt = -1;
91 static gint ett_tn3270e_subopt = -1;
92 static gint ett_xauth_subopt = -1;
93 static gint ett_charset_subopt = -1;
94 static gint ett_rsp_subopt = -1;
95 static gint ett_comport_subopt = -1;
97 static dissector_handle_t tn3270_handle;
99 /* Some defines for Telnet */
101 #define TCP_PORT_TELNET 23
127 NO_LENGTH, /* option has no data, hence no length */
128 FIXED_LENGTH, /* option always has the same length */
129 VARIABLE_LENGTH /* option is variable-length - optlen is minimum */
132 /* Member of table of IP or TCP options. */
133 typedef struct tn_opt {
134 const char *name; /* name of option */
135 gint *subtree_index; /* pointer to subtree index for option */
136 tn_opt_len_type len_type; /* type of option length field */
137 int optlen; /* value length should be (minimum if VARIABLE) */
138 void (*dissect)(packet_info *pinfo, const char *, tvbuff_t *, int, int, proto_tree *);
139 /* routine to dissect option */
143 check_for_tn3270(packet_info *pinfo _U_, const char *optname, const char *terminaltype)
146 if (strcmp(optname,"Terminal Type") != 0) {
150 if ((strcmp(terminaltype,"IBM-3278-2-E") == 0) || (strcmp(terminaltype,"IBM-3278-2") == 0) ||
151 (strcmp(terminaltype,"IBM-3278-3") == 0) || (strcmp(terminaltype,"IBM-3278-4") == 0) ||
152 (strcmp(terminaltype,"IBM-3278-5") == 0) || (strcmp(terminaltype,"IBM-3277-2") == 0) ||
153 (strcmp(terminaltype,"IBM-3279-3") == 0) || (strcmp(terminaltype,"IBM-3279-4") == 0) ||
154 (strcmp(terminaltype,"IBM-3279-2-E") == 0) || (strcmp(terminaltype,"IBM-3279-2") == 0) ||
155 (strcmp(terminaltype,"IBM-3279-4-E") == 0))
156 add_tn3270_conversation(pinfo, 0);
161 dissect_string_subopt(packet_info *pinfo _U_, const char *optname, tvbuff_t *tvb, int offset, int len,
166 cmd = tvb_get_guint8(tvb, offset);
170 proto_tree_add_text(tree, tvb, offset, 1, "Here's my %s", optname);
174 proto_tree_add_text(tree, tvb, offset, len, "Value: %s",
175 tvb_format_text(tvb, offset, len));
177 check_for_tn3270(pinfo, optname, tvb_format_text(tvb, offset, len));
181 proto_tree_add_text(tree, tvb, offset, 1, "Send your %s", optname);
185 proto_tree_add_text(tree, tvb, offset, len, "Extra data");
189 proto_tree_add_text(tree, tvb, offset, 1, "Invalid %s subcommand %u",
194 proto_tree_add_text(tree, tvb, offset, len, "Subcommand data");
200 dissect_tn3270_regime_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
201 int len, proto_tree *tree)
203 #define TN3270_REGIME_ARE 0x01
204 #define TN3270_REGIME_IS 0x00
209 cmd = tvb_get_guint8(tvb, offset);
211 case TN3270_REGIME_ARE:
212 case TN3270_REGIME_IS:
213 if (cmd == TN3270_REGIME_ARE) {
214 proto_tree_add_text(tree, tvb, offset, 1, "ARE");
215 add_tn3270_conversation(pinfo, 0);
217 proto_tree_add_text(tree, tvb, offset, 1, "IS");
219 proto_tree_add_text(tree, tvb, offset + 1, len - 1, "%s",
220 tvb_format_text(tvb, offset + 1, len - 1));
225 proto_tree_add_text(tree, tvb, offset, 1, "Bogus value: %u", cmd);
234 #define TN3270_ASSOCIATE 0x00
235 #define TN3270_CONNECT 0x01
236 #define TN3270_DEVICE_TYPE 0x02
237 #define TN3270_FUNCTIONS 0x03
238 #define TN3270_IS 0x04
239 #define TN3270_REASON 0x05
240 #define TN3270_REJECT 0x06
241 #define TN3270_REQUEST 0x07
242 #define TN3270_SEND 0x08
244 #define TN3270_CONN_PARTNER 0x00
245 #define TN3270_DEVICE_IN_USE 0x01
246 #define TN3270_INV_ASSOCIATE 0x02
247 #define TN3270_INV_DEVICE_NAME 0x03
248 #define TN3270_INV_DEVICE_TYPE 0x04
249 #define TN3270_TYPE_NAME_ERROR 0x05
250 #define TN3270_UNKNOWN_ERROR 0x06
251 #define TN3270_UNSUPPORTED_REQ 0x07
253 #define TN3270_BIND_IMAGE 0x00
254 #define TN3270_DATA_STREAM_CTL 0x01
255 #define TN3270_RESPONSES 0x02
256 #define TN3270_SCS_CTL_CODES 0x03
257 #define TN3270_SYSREQ 0x04
260 dissect_tn3270e_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
261 int len, proto_tree *tree)
266 int connect_offset = 0;
270 cmd = tvb_get_guint8(tvb, offset);
272 case TN3270_ASSOCIATE:
273 proto_tree_add_text(tree, tvb, offset, 1, "ASSOCIATE");
276 proto_tree_add_text(tree, tvb, offset, 1, "CONNECT");
277 proto_tree_add_text(tree, tvb, offset + 1, len, "%s",
278 tvb_format_text(tvb, offset + 1, len - 1));
282 case TN3270_DEVICE_TYPE:
283 proto_tree_add_text(tree, tvb, offset, 1, "DEVICE-TYPE");
285 case TN3270_FUNCTIONS:
286 proto_tree_add_text(tree, tvb, offset, 1, "FUNCTIONS");
289 proto_tree_add_text(tree, tvb, offset, 1, "IS");
290 device_type = tvb_get_guint8(tvb, offset-1);
291 if (device_type == TN3270_DEVICE_TYPE) {
292 /* If there is a terminal type to display, then it will be followed by CONNECT */
293 connect_offset = tvb_find_guint8(tvb, offset + 1, len, TN3270_CONNECT);
294 if (connect_offset != -1) {
295 datalen = connect_offset - (offset + 1);
297 proto_tree_add_text(tree, tvb, offset + 1, datalen, "%s",
298 tvb_format_text(tvb, offset + 1, datalen));
306 proto_tree_add_text(tree, tvb, offset, 1, "REASON");
309 rsn = tvb_get_guint8(tvb, offset);
311 case TN3270_CONN_PARTNER:
312 proto_tree_add_text(tree, tvb, offset, 1, "CONN-PARTNER");
314 case TN3270_DEVICE_IN_USE:
315 proto_tree_add_text(tree, tvb, offset, 1, "DEVICE-IN-USE");
317 case TN3270_INV_ASSOCIATE:
318 proto_tree_add_text(tree, tvb, offset, 1, "INV-ASSOCIATE");
320 case TN3270_INV_DEVICE_NAME:
321 proto_tree_add_text(tree, tvb, offset, 1, "INV-DEVICE-NAME");
323 case TN3270_INV_DEVICE_TYPE:
324 proto_tree_add_text(tree, tvb, offset, 1, "INV-DEVICE-TYPE");
326 case TN3270_TYPE_NAME_ERROR:
327 proto_tree_add_text(tree, tvb, offset, 1, "TYPE-NAME-ERROR");
329 case TN3270_UNKNOWN_ERROR:
330 proto_tree_add_text(tree, tvb, offset, 1, "UNKNOWN-ERROR");
332 case TN3270_UNSUPPORTED_REQ:
333 proto_tree_add_text(tree, tvb, offset, 1, "UNSUPPORTED-REQ");
336 proto_tree_add_text(tree, tvb, offset, 1, "Bogus value: %u", rsn);
341 proto_tree_add_text(tree, tvb, offset, 1, "REJECT");
344 add_tn3270_conversation(pinfo, 1);
345 proto_tree_add_text(tree, tvb, offset, 1, "REQUEST");
346 device_type = tvb_get_guint8(tvb, offset-1);
347 if (device_type == TN3270_DEVICE_TYPE) {
348 proto_tree_add_text(tree, tvb, offset + 1, len, "%s",
349 tvb_format_text(tvb, offset + 1, len - 1));
352 }else if (device_type == TN3270_FUNCTIONS) {
354 while (len > 0 && fn < 5) {
355 rsn = tvb_get_guint8(tvb, offset);
357 case TN3270_BIND_IMAGE:
358 proto_tree_add_text(tree, tvb, offset, 1, "BIND-IMAGE");
360 case TN3270_DATA_STREAM_CTL:
361 proto_tree_add_text(tree, tvb, offset, 1, "DATA-STREAM-CTL");
363 case TN3270_RESPONSES:
364 proto_tree_add_text(tree, tvb, offset, 1, "RESPONSES");
366 case TN3270_SCS_CTL_CODES:
367 proto_tree_add_text(tree, tvb, offset, 1, "SCS-CTL-CODES");
370 proto_tree_add_text(tree, tvb, offset, 1, "SYSREQ");
382 proto_tree_add_text(tree, tvb, offset, 1, "SEND");
385 proto_tree_add_text(tree, tvb, offset, 1, "Bogus value: %u", cmd);
395 dissect_outmark_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
396 int len, proto_tree *tree)
399 int gs_offset, datalen;
402 cmd = tvb_get_guint8(tvb, offset);
406 proto_tree_add_text(tree, tvb, offset, 1, "ACK");
410 proto_tree_add_text(tree, tvb, offset, 1, "NAK");
414 proto_tree_add_text(tree, tvb, offset, 1, "Default");
418 proto_tree_add_text(tree, tvb, offset, 1, "Top");
422 proto_tree_add_text(tree, tvb, offset, 1, "Bottom");
426 proto_tree_add_text(tree, tvb, offset, 1, "Left");
430 proto_tree_add_text(tree, tvb, offset, 1, "Right");
434 proto_tree_add_text(tree, tvb, offset, 1, "Bogus value: %u", cmd);
441 gs_offset = tvb_find_guint8(tvb, offset, len, 29);
442 if (gs_offset == -1) {
443 /* None found - run to the end of the packet. */
444 gs_offset = offset + len;
446 datalen = gs_offset - offset;
448 proto_tree_add_text(tree, tvb, offset, datalen, "Banner: %s",
449 tvb_format_text(tvb, offset, datalen));
457 dissect_htstops_subopt(packet_info *pinfo _U_, const char *optname, tvbuff_t *tvb, int offset, int len,
463 cmd = tvb_get_guint8(tvb, offset);
467 proto_tree_add_text(tree, tvb, offset, 1, "Here's my %s", optname);
473 proto_tree_add_text(tree, tvb, offset, 1, "Send your %s", optname);
479 proto_tree_add_text(tree, tvb, offset, 1, "Invalid %s subcommand %u",
484 proto_tree_add_text(tree, tvb, offset, len, "Subcommand data");
489 tabval = tvb_get_guint8(tvb, offset);
493 proto_tree_add_text(tree, tvb, offset, 1,
494 "Sender wants to handle tab stops");
498 proto_tree_add_text(tree, tvb, offset, 1,
499 "Sender wants receiver to handle tab stop at %u",
507 proto_tree_add_text(tree, tvb, offset, 1,
508 "Invalid value: %u", tabval);
512 proto_tree_add_text(tree, tvb, offset, 1,
513 "Sender wants receiver to handle tab stops");
522 dissect_naws_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
523 int len _U_, proto_tree *tree)
525 proto_tree_add_text(tree, tvb, offset, 2, "Width: %u",
526 tvb_get_ntohs(tvb, offset));
528 proto_tree_add_text(tree, tvb, offset, 2, "Height: %u",
529 tvb_get_ntohs(tvb, offset));
532 /* BEGIN RFC-2217 (COM Port Control) Definitions */
534 #define TNCOMPORT_SIGNATURE 0
535 #define TNCOMPORT_SETBAUDRATE 1
536 #define TNCOMPORT_SETDATASIZE 2
537 #define TNCOMPORT_SETPARITY 3
538 #define TNCOMPORT_SETSTOPSIZE 4
539 #define TNCOMPORT_SETCONTROL 5
540 #define TNCOMPORT_NOTIFYLINESTATE 6
541 #define TNCOMPORT_NOTIFYMODEMSTATE 7
542 #define TNCOMPORT_FLOWCONTROLSUSPEND 8
543 #define TNCOMPORT_FLOWCONTROLRESUME 9
544 #define TNCOMPORT_SETLINESTATEMASK 10
545 #define TNCOMPORT_SETMODEMSTATEMASK 11
546 #define TNCOMPORT_PURGEDATA 12
548 /* END RFC-2217 (COM Port Control) Definitions */
551 dissect_comport_subopt(packet_info *pinfo _U_, const char *optname, tvbuff_t *tvb, int offset, int len,
553 {static const char *datasizes[] = {
564 static const char *parities[] = {
572 static const char *stops[] = {
578 static const char *control[] = {
579 "Output Flow Control Request",
581 "Output Flow: XON/XOFF",
582 "Output Flow: CTS/RTS",
592 "Input Flow Control Request",
594 "Input Flow: XON/XOFF",
595 "Input Flow: CTS/RTS",
600 static const char *linestate_bits[] = {
606 "Transfer Holding Register Empty",
607 "Transfer Shift Register Empty",
610 static const char *modemstate_bits[] = {
620 static const char *purges[] = {
631 cmd = tvb_get_guint8(tvb, offset);
632 isservercmd = cmd > 99;
633 cmd = (isservercmd) ? (cmd - 100) : cmd;
634 source = (isservercmd) ? "Server" : "Client";
637 case TNCOMPORT_SIGNATURE:
640 proto_tree_add_text(tree, tvb, offset, 1, "%s Requests Signature",source);
642 guint8 *sig = tvb_get_ephemeral_string(tvb, offset + 1, len);
643 proto_tree_add_text(tree, tvb, offset, 1 + len, "%s Signature: %s",source, sig);
647 case TNCOMPORT_SETBAUDRATE:
650 guint32 baud = tvb_get_ntohl(tvb, offset+1);
652 proto_tree_add_text(tree, tvb, offset, 5, "%s Requests Baud Rate",source);
654 proto_tree_add_text(tree, tvb, offset, 5, "%s Baud Rate: %d",source,baud);
657 proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Baud Rate Packet>",source);
661 case TNCOMPORT_SETDATASIZE:
664 guint8 datasize = tvb_get_guint8(tvb, offset+1);
665 const char *ds = (datasize > 8) ? "<invalid>" : datasizes[datasize];
666 proto_tree_add_text(tree, tvb, offset, 2, "%s Data Size: %s",source,ds);
668 proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Data Size Packet>",source);
672 case TNCOMPORT_SETPARITY:
675 guint8 parity = tvb_get_guint8(tvb, offset+1);
676 const char *pr = (parity > 5) ? "<invalid>" : parities[parity];
677 proto_tree_add_text(tree, tvb, offset, 2, "%s Parity: %s",source,pr);
679 proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Parity Packet>",source);
683 case TNCOMPORT_SETSTOPSIZE:
686 guint8 stop = tvb_get_guint8(tvb, offset+1);
687 const char *st = (stop > 3) ? "<invalid>" : stops[stop];
688 proto_tree_add_text(tree, tvb, offset, 2, "%s Stop: %s",source,st);
690 proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Stop Packet>",source);
694 case TNCOMPORT_SETCONTROL:
697 guint8 crt = tvb_get_guint8(tvb, offset+1);
698 const char *c = (crt > 19) ? "Control: <invalid>" : control[crt];
699 proto_tree_add_text(tree, tvb, offset, 2, "%s %s",source,c);
701 proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Control Packet>",source);
705 case TNCOMPORT_SETLINESTATEMASK:
706 case TNCOMPORT_NOTIFYLINESTATE:
709 const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
710 "%s Set Linestate Mask: %s" : "%s Linestate: %s";
712 guint8 ls = tvb_get_guint8(tvb, offset+1);
716 for (idx = 0; idx < 8; idx++) {
719 if (print_count != 0) {
720 g_strlcat(ls_buffer,", ",512);
722 g_strlcat(ls_buffer,linestate_bits[idx], 512);
727 proto_tree_add_text(tree, tvb, offset, 2, print_pattern, source, ls_buffer);
729 const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
730 "%s <Invalid Linestate Mask>" : "%s <Invalid Linestate Packet>";
731 proto_tree_add_text(tree, tvb, offset, 1 + len, print_pattern, source);
735 case TNCOMPORT_SETMODEMSTATEMASK:
736 case TNCOMPORT_NOTIFYMODEMSTATE:
739 const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
740 "%s Set Modemstate Mask: %s" : "%s Modemstate: %s";
742 guint8 ms = tvb_get_guint8(tvb, offset+1);
746 for (idx = 0; idx < 8; idx++) {
749 if (print_count != 0) {
750 g_strlcat(ms_buffer,", ",256);
752 g_strlcat(ms_buffer,modemstate_bits[idx],256);
757 proto_tree_add_text(tree, tvb, offset, 2, print_pattern, source, ms_buffer);
759 const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
760 "%s <Invalid Modemstate Mask>" : "%s <Invalid Modemstate Packet>";
761 proto_tree_add_text(tree, tvb, offset, 1 + len, print_pattern, source);
765 case TNCOMPORT_FLOWCONTROLSUSPEND:
767 proto_tree_add_text(tree, tvb, offset, 1, "%s Flow Control Suspend",source);
770 case TNCOMPORT_FLOWCONTROLRESUME:
772 proto_tree_add_text(tree, tvb, offset, 1, "%s Flow Control Resume",source);
775 case TNCOMPORT_PURGEDATA:
778 guint8 purge = tvb_get_guint8(tvb, offset+1);
779 const char *p = (purge > 3) ? "<Purge invalid>" : purges[purge];
780 proto_tree_add_text(tree, tvb, offset, 2, "%s %s",source,p);
782 proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Purge Packet>",source);
787 proto_tree_add_text(tree, tvb, offset, 1, "Invalid %s subcommand %u",
792 proto_tree_add_text(tree, tvb, offset, len, "Subcommand data");
798 static const value_string rfc_opt_vals[] = {
801 { 2, "RESTART-ANY" },
802 { 3, "RESTART-XON" },
807 dissect_rfc_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset,
808 int len _U_, proto_tree *tree)
812 cmd = tvb_get_guint8(tvb, offset);
813 proto_tree_add_text(tree, tvb, offset, 2, "%s",
814 val_to_str(cmd, rfc_opt_vals, "Unknown (%u)"));
818 #define TN_ENC_SUPPORT 1
819 #define TN_ENC_REPLY 2
820 #define TN_ENC_START 3
822 #define TN_ENC_REQUEST_START 5
823 #define TN_ENC_REQUEST_END 6
824 #define TN_ENC_ENC_KEYID 7
825 #define TN_ENC_DEC_KEYID 8
826 static const value_string enc_cmd_vals[] = {
828 { TN_ENC_SUPPORT, "SUPPORT" },
829 { TN_ENC_REPLY, "REPLY" },
830 { TN_ENC_START, "START" },
831 { TN_ENC_END, "END" },
832 { TN_ENC_REQUEST_START, "REQUEST-START" },
833 { TN_ENC_REQUEST_END, "REQUEST-END" },
834 { TN_ENC_ENC_KEYID, "ENC_KEYID" },
835 { TN_ENC_DEC_KEYID, "DEC_KEYID" },
839 #define TN_ENCTYPE_NULL 0
840 #define TN_ENCTYPE_DES_CFB64 1
841 #define TN_ENCTYPE_DES_OFB64 2
842 #define TN_ENCTYPE_DES3_CFB64 3
843 #define TN_ENCTYPE_DES3_OFB64 4
844 #define TN_ENCTYPE_CAST5_40_CFB64 8
845 #define TN_ENCTYPE_CAST5_40_OFB64 9
846 #define TN_ENCTYPE_CAST128_CFB64 10
847 #define TN_ENCTYPE_CAST128_OFB64 11
848 static const value_string enc_type_vals[] = {
849 { TN_ENCTYPE_NULL, "NULL" },
850 { TN_ENCTYPE_DES_CFB64, "DES_CFB64" },
851 { TN_ENCTYPE_DES_OFB64, "DES_OFB64" },
852 { TN_ENCTYPE_DES3_CFB64, "DES3_CFB64" },
853 { TN_ENCTYPE_DES3_OFB64, "DES3_OFB64" },
854 { TN_ENCTYPE_CAST5_40_CFB64, "CAST5_40_CFB64" },
855 { TN_ENCTYPE_CAST5_40_OFB64, "CAST5_40_OFB64" },
856 { TN_ENCTYPE_CAST128_CFB64, "CAST128_CFB64" },
857 { TN_ENCTYPE_CAST128_OFB64, "CAST128_OFB64" },
864 #define TN_AC_REPLY 2
866 static const value_string auth_cmd_vals[] = {
868 { TN_AC_SEND, "SEND" },
869 { TN_AC_REPLY, "REPLY" },
870 { TN_AC_NAME, "NAME" },
882 #define TN_AT_LOKI 10
884 #define TN_AT_KEA_SJ 12
885 #define TN_AT_KEA_SJ_INTEG 13
887 #define TN_AT_NTLM 15
888 static const value_string auth_type_vals[] = {
889 { TN_AT_NULL, "NULL" },
890 { TN_AT_KRB4, "Kerberos v4" },
891 { TN_AT_KRB5, "Kerberos v5" },
892 { TN_AT_SPX, "SPX" },
893 { TN_AT_MINK, "MINK" },
894 { TN_AT_SRP, "SRP" },
895 { TN_AT_RSA, "RSA" },
896 { TN_AT_SSL, "SSL" },
897 { TN_AT_LOKI, "LOKI" },
898 { TN_AT_SSA, "SSA" },
899 { TN_AT_KEA_SJ, "KEA_SJ" },
900 { TN_AT_KEA_SJ_INTEG, "KEA_SJ_INTEG" },
901 { TN_AT_DSS, "DSS" },
902 { TN_AT_NTLM, "NTLM" },
905 static const true_false_string auth_mod_cred_fwd = {
906 "Client WILL forward auth creds",
907 "Client will NOT forward auth creds"
909 static const true_false_string auth_mod_who = {
910 "Mask server to client",
911 "Mask client to server"
913 static const true_false_string auth_mod_how = {
914 "MUTUAL authentication",
915 "One Way authentication"
917 #define TN_AM_OFF 0x00
918 #define TN_AM_USING_TELOPT 0x01
919 #define TN_AM_AFTER_EXCHANGE 0x02
920 #define TN_AM_RESERVED 0x04
921 static const value_string auth_mod_enc[] = {
922 { TN_AM_OFF, "Off" },
923 { TN_AM_USING_TELOPT, "Telnet Options" },
924 { TN_AM_AFTER_EXCHANGE, "After Exchange" },
925 { TN_AM_RESERVED, "Reserved" },
928 #define TN_KRB5_TYPE_AUTH 0
929 #define TN_KRB5_TYPE_REJECT 1
930 #define TN_KRB5_TYPE_ACCEPT 2
931 #define TN_KRB5_TYPE_RESPONSE 3
932 #define TN_KRB5_TYPE_FORWARD 4
933 #define TN_KRB5_TYPE_FORWARD_ACCEPT 5
934 #define TN_KRB5_TYPE_FORWARD_REJECT 6
935 static const value_string auth_krb5_types[] = {
936 { TN_KRB5_TYPE_AUTH, "Auth" },
937 { TN_KRB5_TYPE_REJECT, "Reject" },
938 { TN_KRB5_TYPE_ACCEPT, "Accept" },
939 { TN_KRB5_TYPE_RESPONSE, "Response" },
940 { TN_KRB5_TYPE_FORWARD, "Forward" },
941 { TN_KRB5_TYPE_FORWARD_ACCEPT, "Forward Accept" },
942 { TN_KRB5_TYPE_FORWARD_REJECT, "Forward Reject" },
946 dissect_authentication_type_pair(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, proto_tree *tree)
950 type=tvb_get_guint8(tvb, offset);
951 proto_tree_add_uint(tree, hf_telnet_auth_type, tvb, offset, 1, type);
953 mod=tvb_get_guint8(tvb, offset+1);
954 proto_tree_add_uint(tree, hf_telnet_auth_mod_enc, tvb, offset+1, 1, mod);
955 proto_tree_add_boolean(tree, hf_telnet_auth_mod_cred_fwd, tvb, offset+1, 1, mod);
956 proto_tree_add_boolean(tree, hf_telnet_auth_mod_how, tvb, offset+1, 1, mod);
957 proto_tree_add_boolean(tree, hf_telnet_auth_mod_who, tvb, offset+1, 1, mod);
960 /* no kerberos blobs are ever >10kb ? (arbitrary limit) */
961 #define MAX_KRB5_BLOB_LEN 10240
964 unescape_and_tvbuffify_telnet_option(packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
972 if(len>=MAX_KRB5_BLOB_LEN)
975 spos=tvb_get_ptr(tvb, offset, len);
981 if((spos[0]==0xff) && (spos[1]==0xff)){
991 krb5_tvb = tvb_new_child_real_data(tvb, buf, len-skip, len-skip);
992 tvb_set_free_cb(krb5_tvb, g_free);
993 add_new_data_source(pinfo, krb5_tvb, "Unpacked Telnet Option");
1001 dissect_krb5_authentication_data(packet_info *pinfo, tvbuff_t *tvb, int offset, int len, proto_tree *tree, guint8 acmd)
1006 dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1011 krb5_cmd=tvb_get_guint8(tvb, offset);
1012 proto_tree_add_uint(tree, hf_telnet_auth_krb5_type, tvb, offset, 1, krb5_cmd);
1017 /* IAC SB AUTHENTICATION IS <authentication-type-pair> AUTH <Kerberos V5 KRB_AP_REQ message> IAC SE */
1018 if((acmd==TN_AC_IS)&&(krb5_cmd==TN_KRB5_TYPE_AUTH)){
1020 krb5_tvb=unescape_and_tvbuffify_telnet_option(pinfo, tvb, offset, len);
1022 dissect_kerberos_main(krb5_tvb, pinfo, tree, FALSE, NULL);
1024 proto_tree_add_text(tree, tvb, offset, len, "Kerberos blob (too long to dissect - length %u > %u",
1025 len, MAX_KRB5_BLOB_LEN);
1031 /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> ACCEPT IAC SE */
1032 /* nothing more to dissect */
1036 /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> REJECT <optional reason for rejection> IAC SE*/
1040 /* IAC SB AUTHENTICATION REPLY <authentication-type-pair> RESPONSE <KRB_AP_REP message> IAC SE */
1041 if((acmd==TN_AC_REPLY)&&(krb5_cmd==TN_KRB5_TYPE_RESPONSE)){
1043 krb5_tvb=unescape_and_tvbuffify_telnet_option(pinfo, tvb, offset, len);
1044 dissect_kerberos_main(krb5_tvb, pinfo, tree, FALSE, NULL);
1049 /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD <KRB_CRED message> IAC SE */
1050 /* XXX unclear what this one looks like */
1053 /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_ACCEPT IAC SE */
1054 /* nothing more to dissect */
1058 /* IAC SB AUTHENTICATION <authentication-type-pair> FORWARD_REJECT */
1059 /* nothing more to dissect */
1063 dissect_authentication_subopt(packet_info *pinfo, const char *optname _U_, tvbuff_t *tvb, int offset, int len, proto_tree *tree)
1068 /* XXX here we should really split it up in a conversation struct keeping
1069 track of what method we actually use and not just assume it is always
1072 acmd=tvb_get_guint8(tvb, offset);
1073 proto_tree_add_uint(tree, hf_telnet_auth_cmd, tvb, offset, 1, acmd);
1080 /* XXX here we shouldnt just assume it is krb5 */
1081 dissect_krb5_authentication_data(pinfo, tvb, offset, len, tree, acmd);
1085 dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1093 tvb_memcpy(tvb, (guint8*)name, offset, len);
1096 name="<...name too long...>";
1098 proto_tree_add_string(tree, hf_telnet_auth_name, tvb, offset, len, name);
1103 /* This function only uses the octet in the buffer at 'offset' */
1104 static void dissect_encryption_type(tvbuff_t *tvb, int offset, proto_tree *tree) {
1106 etype = tvb_get_guint8(tvb, offset);
1107 proto_tree_add_uint(tree, hf_telnet_enc_type, tvb, offset, 1, etype);
1111 dissect_encryption_subopt(packet_info *pinfo _U_, const char *optname _U_, tvbuff_t *tvb, int offset, int len, proto_tree *tree)
1113 guint8 ecmd, key_first_octet;
1115 ecmd = tvb_get_guint8(tvb, offset);
1116 proto_tree_add_uint(tree, hf_telnet_enc_cmd, tvb, offset, 1, ecmd);
1124 /* encryption type, type-specific data ... */
1126 dissect_encryption_type(tvb, offset, tree);
1129 proto_tree_add_text(tree, tvb, offset, len, "Type-specific data");
1133 case TN_ENC_SUPPORT:
1134 /* list of encryption types ... */
1136 dissect_encryption_type(tvb, offset, tree);
1145 key_first_octet = tvb_get_guint8(tvb, offset);
1146 proto_tree_add_text(tree, tvb, offset, len, (key_first_octet == 0) ? "Default key" : "Key ID");
1154 case TN_ENC_REQUEST_START:
1155 /* (optional) keyid */
1157 proto_tree_add_text(tree, tvb, offset, len, "Key ID (advisory)");
1160 case TN_ENC_REQUEST_END:
1164 case TN_ENC_ENC_KEYID:
1165 case TN_ENC_DEC_KEYID:
1166 /* (optional) keyid - if not supplied, there are no more known keys */
1168 proto_tree_add_text(tree, tvb, offset, len, "Key ID");
1172 proto_tree_add_text(tree, tvb, offset, len, "Unknown command");
1176 static tn_opt options[] = {
1178 "Binary Transmission", /* RFC 856 */
1179 NULL, /* no suboption negotiation */
1185 "Echo", /* RFC 857 */
1186 NULL, /* no suboption negotiation */
1192 "Reconnection", /* DOD Protocol Handbook */
1199 "Suppress Go Ahead", /* RFC 858 */
1200 NULL, /* no suboption negotiation */
1206 "Approx Message Size Negotiation", /* Ethernet spec(!) */
1213 "Status", /* RFC 859 */
1217 NULL /* XXX - fill me in */
1220 "Timing Mark", /* RFC 860 */
1221 NULL, /* no suboption negotiation */
1227 "Remote Controlled Trans and Echo", /* RFC 726 */
1231 NULL /* XXX - fill me in */
1234 "Output Line Width", /* DOD Protocol Handbook */
1236 VARIABLE_LENGTH, /* XXX - fill me in */
1237 0, /* XXX - fill me in */
1238 NULL /* XXX - fill me in */
1241 "Output Page Size", /* DOD Protocol Handbook */
1243 VARIABLE_LENGTH, /* XXX - fill me in */
1244 0, /* XXX - fill me in */
1245 NULL /* XXX - fill me in */
1248 "Output Carriage-Return Disposition", /* RFC 652 */
1252 NULL /* XXX - fill me in */
1255 "Output Horizontal Tab Stops", /* RFC 653 */
1256 &ett_htstops_subopt,
1259 dissect_htstops_subopt
1262 "Output Horizontal Tab Disposition", /* RFC 654 */
1266 NULL /* XXX - fill me in */
1269 "Output Formfeed Disposition", /* RFC 655 */
1273 NULL /* XXX - fill me in */
1276 "Output Vertical Tabstops", /* RFC 656 */
1277 &ett_vtstops_subopt,
1280 NULL /* XXX - fill me in */
1283 "Output Vertical Tab Disposition", /* RFC 657 */
1287 NULL /* XXX - fill me in */
1290 "Output Linefeed Disposition", /* RFC 658 */
1294 NULL /* XXX - fill me in */
1297 "Extended ASCII", /* RFC 698 */
1301 NULL /* XXX - fill me in */
1304 "Logout", /* RFC 727 */
1305 NULL, /* no suboption negotiation */
1311 "Byte Macro", /* RFC 735 */
1312 &ett_bytemacro_subopt,
1315 NULL /* XXX - fill me in */
1318 "Data Entry Terminal", /* RFC 732, RFC 1043 */
1322 NULL /* XXX - fill me in */
1325 "SUPDUP", /* RFC 734, RFC 736 */
1326 NULL, /* no suboption negotiation */
1332 "SUPDUP Output", /* RFC 749 */
1333 &ett_supdupout_subopt,
1336 NULL /* XXX - fill me in */
1339 "Send Location", /* RFC 779 */
1340 &ett_sendloc_subopt,
1343 NULL /* XXX - fill me in */
1346 "Terminal Type", /* RFC 1091 */
1347 &ett_termtype_subopt,
1350 dissect_string_subopt
1353 "End of Record", /* RFC 885 */
1354 NULL, /* no suboption negotiation */
1360 "TACACS User Identification", /* RFC 927 */
1361 &ett_tacacsui_subopt,
1364 NULL /* XXX - fill me in */
1367 "Output Marking", /* RFC 933 */
1368 &ett_outmark_subopt,
1371 dissect_outmark_subopt,
1374 "Terminal Location Number", /* RFC 946 */
1375 &ett_tlocnum_subopt,
1378 NULL /* XXX - fill me in */
1381 "Telnet 3270 Regime", /* RFC 1041 */
1382 &ett_tn3270reg_subopt,
1385 dissect_tn3270_regime_subopt
1388 "X.3 PAD", /* RFC 1053 */
1392 NULL /* XXX - fill me in */
1395 "Negotiate About Window Size", /* RFC 1073, DW183 */
1402 "Terminal Speed", /* RFC 1079 */
1406 NULL /* XXX - fill me in */
1409 "Remote Flow Control", /* RFC 1372 */
1416 "Linemode", /* RFC 1184 */
1417 &ett_linemode_subopt,
1420 NULL /* XXX - fill me in */
1423 "X Display Location", /* RFC 1096 */
1424 &ett_xdpyloc_subopt,
1427 dissect_string_subopt
1430 "Environment Option", /* RFC 1408, RFC 1571 */
1434 NULL /* XXX - fill me in */
1437 "Authentication Option", /* RFC 2941 */
1441 dissect_authentication_subopt
1444 "Encryption Option", /* RFC 2946 */
1448 dissect_encryption_subopt
1451 "New Environment Option", /* RFC 1572 */
1455 NULL /* XXX - fill me in */
1458 "TN3270E", /* RFC 1647 */
1459 &ett_tn3270e_subopt,
1462 dissect_tn3270e_subopt
1465 "XAUTH", /* XAUTH */
1469 NULL /* XXX - fill me in */
1472 "CHARSET", /* CHARSET */
1473 &ett_charset_subopt,
1476 NULL /* XXX - fill me in */
1479 "Remote Serial Port", /* Remote Serial Port */
1483 NULL /* XXX - fill me in */
1486 "COM Port Control", /* RFC 2217 */
1487 &ett_comport_subopt,
1490 dissect_comport_subopt
1495 #define NOPTIONS (sizeof options / sizeof options[0])
1498 telnet_sub_option(packet_info *pinfo, proto_tree *telnet_tree, tvbuff_t *tvb, int start_offset)
1500 proto_tree *ti, *option_tree;
1501 int offset = start_offset;
1505 gint ett = ett_telnet_subopt;
1508 tvbuff_t * unescaped_tvb;
1509 void (*dissect)(packet_info *, const char *, tvbuff_t *, int, int, proto_tree *);
1514 * As data with value iac (0xff) is possible, this value must be escaped
1515 * with iac (rfc 854).
1519 offset += 2; /* skip IAC and SB */
1521 /* Get the option code */
1522 opt_byte = tvb_get_guint8(tvb, offset);
1523 if (opt_byte >= NOPTIONS) {
1524 opt = "<unknown option>";
1527 opt = options[opt_byte].name;
1528 if (options[opt_byte].subtree_index != NULL)
1529 ett = *(options[opt_byte].subtree_index);
1530 dissect = options[opt_byte].dissect;
1534 /* Search for an unescaped IAC. */
1535 cur_offset = offset;
1537 len = tvb_length_remaining(tvb, offset);
1539 iac_offset = tvb_find_guint8(tvb, cur_offset, len, TN_IAC);
1541 if (iac_offset == -1) {
1542 /* None found - run to the end of the packet. */
1545 if (((guint)(iac_offset + 1) >= len) ||
1546 (tvb_get_guint8(tvb, iac_offset + 1) != TN_IAC)) {
1547 /* We really found a single IAC, so we're done */
1548 offset = iac_offset;
1551 * We saw an escaped IAC, so we have to move ahead to the
1555 cur_offset = iac_offset + 2;
1560 } while (!iac_found);
1562 subneg_len = offset - start_offset;
1564 ti = proto_tree_add_text(telnet_tree, tvb, start_offset, subneg_len,
1565 "Suboption Begin: %s", opt);
1566 option_tree = proto_item_add_subtree(ti, ett);
1567 start_offset += 3; /* skip IAC, SB, and option code */
1570 if (subneg_len > 0) {
1572 /* Now dissect the suboption parameters. */
1573 if (dissect != NULL) {
1575 switch (options[opt_byte].len_type) {
1578 /* There isn't supposed to *be* sub-option negotiation for this. */
1579 proto_tree_add_text(option_tree, tvb, start_offset, subneg_len,
1580 "Bogus suboption data");
1584 /* Make sure the length is what it's supposed to be. */
1585 if (subneg_len - iac_data != options[opt_byte].optlen) {
1586 proto_tree_add_text(option_tree, tvb, start_offset, subneg_len,
1587 "Suboption parameter length is %d, should be %d",
1588 subneg_len, options[opt_byte].optlen);
1593 case VARIABLE_LENGTH:
1594 /* Make sure the length is greater than the minimum. */
1595 if (subneg_len - iac_data < options[opt_byte].optlen) {
1596 proto_tree_add_text(option_tree, tvb, start_offset, subneg_len,
1597 "Suboption parameter length is %d, should be at least %d",
1598 subneg_len, options[opt_byte].optlen);
1604 /* We have a dissector for this suboption's parameters; call it. */
1606 /* Data is escaped, we have to unescape it. */
1607 unescaped_tvb = unescape_and_tvbuffify_telnet_option(pinfo, tvb, start_offset, subneg_len);
1608 (*dissect)(pinfo, opt, unescaped_tvb, 0, subneg_len - iac_data, option_tree);
1610 (*dissect)(pinfo, opt, tvb, start_offset, subneg_len, option_tree);
1613 /* We don't have a dissector for them; just show them as data. */
1615 /* Data is escaped, we have to unescape it. */
1616 unescaped_tvb = unescape_and_tvbuffify_telnet_option(pinfo, tvb, start_offset, subneg_len);
1617 proto_tree_add_text(option_tree, unescaped_tvb, 0, subneg_len - iac_data,
1620 proto_tree_add_text(option_tree, tvb, start_offset, subneg_len,
1629 telnet_will_wont_do_dont(proto_tree *telnet_tree, tvbuff_t *tvb,
1630 int start_offset, const char *type)
1632 int offset = start_offset;
1636 offset += 2; /* skip IAC and WILL,WONT,DO,DONT} */
1637 opt_byte = tvb_get_guint8(tvb, offset);
1638 if (opt_byte >= NOPTIONS)
1639 opt = "<unknown option>";
1641 opt = options[opt_byte].name;
1644 proto_tree_add_text(telnet_tree, tvb, start_offset, 3,
1645 "Command: %s %s", type, opt);
1650 telnet_command(packet_info *pinfo, proto_tree *telnet_tree, tvbuff_t *tvb, int start_offset)
1652 int offset = start_offset;
1655 offset += 1; /* skip IAC */
1656 optcode = tvb_get_guint8(tvb, offset);
1661 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1662 "Command: End of File");
1666 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1667 "Command: Suspend Current Process");
1671 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1672 "Command: Abort Process");
1676 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1677 "Command: End of Record");
1681 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1682 "Command: Suboption End");
1686 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1687 "Command: No Operation");
1691 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1692 "Command: Data Mark");
1696 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1701 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1702 "Command: Interrupt Process");
1706 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1707 "Command: Abort Output");
1711 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1712 "Command: Are You There?");
1716 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1717 "Command: Escape Character");
1721 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1722 "Command: Erase Line");
1726 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1727 "Command: Go Ahead");
1731 offset = telnet_sub_option(pinfo, telnet_tree, tvb, start_offset);
1735 offset = telnet_will_wont_do_dont(telnet_tree, tvb, start_offset,
1740 offset = telnet_will_wont_do_dont(telnet_tree, tvb, start_offset,
1745 offset = telnet_will_wont_do_dont(telnet_tree, tvb, start_offset,
1750 offset = telnet_will_wont_do_dont(telnet_tree, tvb, start_offset,
1755 proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
1756 "Command: Unknown (0x%02x)", optcode);
1764 telnet_add_text(proto_tree *tree, tvbuff_t *tvb, int offset, int len)
1769 gboolean last_char_was_cr;
1771 while (len != 0 && tvb_offset_exists(tvb, offset)) {
1773 * Find the end of the line.
1775 linelen = tvb_find_line_end(tvb, offset, len, &next_offset, FALSE);
1776 len -= next_offset - offset; /* subtract out the line's characters */
1779 * In Telnet, CR NUL is the way you send a CR by itself in the
1780 * default ASCII mode; don't treat CR by itself as a line ending,
1781 * treat only CR NUL, CR LF, or LF by itself as a line ending.
1783 if (next_offset == offset + linelen + 1 && len >= 1) {
1785 * Well, we saw a one-character line ending, so either it's a CR
1786 * or an LF; we have at least two characters left, including the
1789 * If the line ending is a CR, skip all subsequent CRs; at
1790 * least one capture appeared to have multiple CRs at the end of
1793 if (tvb_get_guint8(tvb, offset + linelen) == '\r') {
1794 last_char_was_cr = TRUE;
1795 while (len != 0 && tvb_offset_exists(tvb, next_offset)) {
1796 c = tvb_get_guint8(tvb, next_offset);
1797 next_offset++; /* skip over that character */
1799 if (c == '\n' || (c == '\0' && last_char_was_cr)) {
1801 * LF is a line ending, whether preceded by CR or not.
1802 * NUL is a line ending if preceded by CR.
1806 last_char_was_cr = (c == '\r');
1812 * Now compute the length of the line *including* the end-of-line
1813 * indication, if any; we display it all.
1815 linelen = next_offset - offset;
1817 proto_tree_add_text(tree, tvb, offset, linelen,
1819 tvb_format_text(tvb, offset, linelen));
1820 offset = next_offset;
1824 static int find_unescaped_iac(tvbuff_t *tvb, int offset, int len)
1826 int iac_offset = offset;
1828 /* If we find an IAC (0XFF), make sure it is not followed by another 0XFF.
1829 Such cases indicate that it is not an IAC at all */
1830 while ((iac_offset = tvb_find_guint8(tvb, iac_offset, len, TN_IAC)) != -1 &&
1831 (tvb_get_guint8(tvb, iac_offset + 1) == TN_IAC))
1834 len = tvb_length_remaining(tvb, iac_offset);
1840 dissect_telnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1842 proto_tree *telnet_tree, *ti;
1846 guint is_tn3270 = 0;
1848 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TELNET");
1850 col_set_str(pinfo->cinfo, COL_INFO, "Telnet Data ...");
1852 is_tn3270 = find_tn3270_conversation(pinfo);
1858 ti = proto_tree_add_item(tree, proto_telnet, tvb, offset, -1, FALSE);
1859 telnet_tree = proto_item_add_subtree(ti, ett_telnet);
1862 * Scan through the buffer looking for an IAC byte.
1864 while ((len = tvb_length_remaining(tvb, offset)) > 0) {
1865 iac_offset = find_unescaped_iac(tvb, offset, len);
1866 if (iac_offset != -1) {
1868 * We found an IAC byte.
1869 * If there's any data before it, add that data to the
1870 * tree, a line at a time.
1872 data_len = iac_offset - offset;
1875 next_tvb = tvb_new_subset(tvb, offset, data_len, data_len);
1876 call_dissector(tn3270_handle, next_tvb, pinfo, telnet_tree);
1878 telnet_add_text(telnet_tree, tvb, offset, data_len);
1881 * Now interpret the command.
1883 offset = telnet_command(pinfo, telnet_tree, tvb, iac_offset);
1885 /* get more data if tn3270 */
1887 pinfo->desegment_offset = offset;
1888 pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
1892 * We found no IAC byte, so what remains in the buffer
1893 * is the last of the data in the packet.
1894 * Add it to the tree, a line at a time, and then quit.
1896 telnet_add_text(telnet_tree, tvb, offset, len);
1904 proto_register_telnet(void)
1906 static hf_register_info hf[] = {
1907 { &hf_telnet_auth_name,
1908 { "Name", "telnet.auth.name", FT_STRING, BASE_NONE,
1909 NULL, 0, "Name of user being authenticated", HFILL }},
1910 { &hf_telnet_auth_cmd,
1911 { "Auth Cmd", "telnet.auth.cmd", FT_UINT8, BASE_DEC,
1912 VALS(auth_cmd_vals), 0, "Authentication Command", HFILL }},
1913 { &hf_telnet_auth_type,
1914 { "Auth Type", "telnet.auth.type", FT_UINT8, BASE_DEC,
1915 VALS(auth_type_vals), 0, "Authentication Type", HFILL }},
1916 { &hf_telnet_auth_mod_cred_fwd,
1917 { "Cred Fwd", "telnet.auth.mod.cred_fwd", FT_BOOLEAN, 8,
1918 TFS(&auth_mod_cred_fwd), 0x08, "Modifier: Whether client will forward creds or not", HFILL }},
1919 { &hf_telnet_auth_mod_who,
1920 { "Who", "telnet.auth.mod.who", FT_BOOLEAN, 8,
1921 TFS(&auth_mod_who), 0x01, "Modifier: Who to mask", HFILL }},
1922 { &hf_telnet_auth_mod_how,
1923 { "How", "telnet.auth.mod.how", FT_BOOLEAN, 8,
1924 TFS(&auth_mod_how), 0x02, "Modifier: How to mask", HFILL }},
1925 { &hf_telnet_auth_mod_enc,
1926 { "Encrypt", "telnet.auth.mod.enc", FT_UINT8, BASE_DEC,
1927 VALS(auth_mod_enc), 0x14, "Modifier: How to enable Encryption", HFILL }},
1928 { &hf_telnet_auth_krb5_type,
1929 { "Command", "telnet.auth.krb5.cmd", FT_UINT8, BASE_DEC,
1930 VALS(auth_krb5_types), 0, "Krb5 Authentication sub-command", HFILL }},
1931 { &hf_telnet_enc_cmd,
1932 { "Enc Cmd", "telnet.enc.cmd", FT_UINT8, BASE_DEC,
1933 VALS(enc_cmd_vals), 0, "Encryption command", HFILL }},
1934 { &hf_telnet_enc_type,
1935 { "Enc Type", "telnet.enc.type", FT_UINT8, BASE_DEC,
1936 VALS(enc_type_vals), 0, "Encryption type", HFILL }},
1938 static gint *ett[] = {
1946 &ett_htstops_subopt,
1949 &ett_vtstops_subopt,
1953 &ett_bytemacro_subopt,
1955 &ett_supdupout_subopt,
1956 &ett_sendloc_subopt,
1957 &ett_termtype_subopt,
1958 &ett_tacacsui_subopt,
1959 &ett_outmark_subopt,
1960 &ett_tlocnum_subopt,
1961 &ett_tn3270reg_subopt,
1966 &ett_linemode_subopt,
1967 &ett_xdpyloc_subopt,
1972 &ett_tn3270e_subopt,
1974 &ett_charset_subopt,
1979 proto_telnet = proto_register_protocol("Telnet", "TELNET", "telnet");
1980 proto_register_field_array(proto_telnet, hf, array_length(hf));
1981 proto_register_subtree_array(ett, array_length(ett));
1985 proto_reg_handoff_telnet(void)
1987 dissector_handle_t telnet_handle;
1989 telnet_handle = create_dissector_handle(dissect_telnet, proto_telnet);
1990 dissector_add("tcp.port", TCP_PORT_TELNET, telnet_handle);
1991 tn3270_handle = find_dissector("tn3270");