MSWSP: add two more Property Sets
[wireshark-wip.git] / epan / dissectors / packet-telnet.c
blobe3121c33e5fb937887030f0edf42e50d8b62c711
1 /* packet-telnet.c
2 * Routines for Telnet packet dissection; see RFC 854 and RFC 855
3 * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
5 * $Id$
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
28 #include "config.h"
30 #include <stdlib.h>
31 #include <string.h>
33 #include <glib.h>
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
144 #define TN_IAC 255
145 #define TN_DONT 254
146 #define TN_DO 253
147 #define TN_WONT 252
148 #define TN_WILL 251
149 #define TN_SB 250
150 #define TN_GA 249
151 #define TN_EL 248
152 #define TN_EC 247
153 #define TN_AYT 246
154 #define TN_AO 245
155 #define TN_IP 244
156 #define TN_BRK 243
157 #define TN_DM 242
158 #define TN_NOP 241
159 #define TN_SE 240
160 #define TN_EOR 239
161 #define TN_ABORT 238
162 #define TN_SUSP 237
163 #define TN_EOF 236
164 #define TN_ARE 1
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" },
174 { TN_BRK, "Break" },
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" },
182 { TN_DO, "Do" },
183 { TN_WONT, "Won't" },
184 { TN_WILL, "Will" },
185 { TN_SB, "Suboption" },
186 { 0, NULL }
189 typedef enum {
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 */
193 } tn_opt_len_type;
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 */
203 } tn_opt;
205 static void
206 check_tn3270_model(packet_info *pinfo _U_, const char *terminaltype)
208 int model;
209 char str_model[2];
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];
218 str_model[1] = '\0';
219 model = atoi(str_model);
220 add_tn3270_conversation(pinfo, 0, model);
224 static void
225 check_for_tn3270(packet_info *pinfo _U_, const char *optname, const char *terminaltype)
227 if (strcmp(optname,"Terminal Type") != 0) {
228 return;
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);
245 static void
246 dissect_string_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, int offset, int len,
247 proto_tree *tree, proto_item *item)
249 guint8 cmd;
251 cmd = tvb_get_guint8(tvb, offset);
252 switch (cmd) {
254 case 0: /* IS */
255 proto_tree_add_text(tree, tvb, offset, 1, "Here's my %s", optname);
256 offset++;
257 len--;
258 if (len > 0) {
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));
262 break;
264 case 1: /* SEND */
265 proto_tree_add_text(tree, tvb, offset, 1, "Send your %s", optname);
266 offset++;
267 len--;
268 if (len > 0)
269 proto_tree_add_text(tree, tvb, offset, len, "Extra data");
270 break;
272 default:
273 expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
275 offset++;
276 len--;
277 if (len > 0)
278 proto_tree_add_text(tree, tvb, offset, len, "Subcommand data");
279 break;
283 static void
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
290 guint8 cmd;
292 while (len > 0) {
293 cmd = tvb_get_guint8(tvb, offset);
294 switch (cmd) {
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);
300 } else {
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);
304 len -= len;
305 return;
306 default:
307 expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Bogus value: %u", cmd);
308 break;
310 offset++;
311 len --;
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
325 /* Reason_codes*/
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
334 /* Function Names*/
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" },
346 { TN3270_IS, "IS" },
347 { TN3270_REASON, "REASON" },
348 { TN3270_REJECT, "REJECT" },
349 { TN3270_REQUEST, "REQUEST" },
350 { TN3270_SEND, "SEND" },
351 { 0, NULL }
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" },
363 { 0, NULL }
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" },
372 { 0, NULL }
375 static void
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_)
380 guint8 cmd;
381 int datalen;
382 int connect_offset = 0;
383 int device_type = 0;
384 int rsn = 0;
386 while (len > 0) {
387 cmd = tvb_get_guint8(tvb, offset);
388 proto_tree_add_item( tree, hf_tn3270_subopt, tvb, offset, 1, ENC_NA );
389 switch (cmd) {
390 case TN3270_CONNECT:
391 proto_tree_add_item( tree, hf_tn3270_connect, tvb, offset + 1, len, ENC_NA|ENC_ASCII );
392 offset += (len - 1);
393 len -= (len - 1);
394 break;
395 case TN3270_IS:
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);
402 if (datalen > 0) {
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));
405 offset += datalen;
406 len -= datalen;
410 break;
411 case TN3270_REASON:
412 offset++;
413 len--;
414 proto_tree_add_item( tree, hf_tn3270_reason, tvb, offset, 1, ENC_NA );
415 break;
416 case TN3270_REQUEST:
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 );
421 offset += (len - 1);
422 len -= (len - 1);
423 }else if (device_type == TN3270_FUNCTIONS) {
424 while (len > 0) {
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)
428 break;
430 offset++;
431 len--;
434 break;
436 offset++;
437 len--;
442 static const value_string telnet_outmark_subopt_cmd_vals[] = {
443 { 6, "ACK" },
444 { 21, "NAK" },
445 { 'D', "Default" },
446 { 'T', "Top" },
447 { 'B', "Bottom" },
448 { 'L', "Left" },
449 { 'R', "Right" },
450 { 0, NULL }
453 static void
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;
459 while (len > 0) {
460 proto_tree_add_item(tree, hf_telnet_outmark_subopt_cmd, tvb, offset, 1, ENC_NA);
462 offset++;
463 len--;
465 /* Look for a GS */
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;
472 if (datalen > 0) {
473 proto_tree_add_item(tree, hf_telnet_outmark_subopt_banner, tvb, offset, datalen, ENC_NA|ENC_ASCII);
474 offset += datalen;
475 len -= datalen;
480 static void
481 dissect_htstops_subopt(packet_info *pinfo, const char *optname, tvbuff_t *tvb, int offset, int len,
482 proto_tree *tree, proto_item *item)
484 guint8 cmd;
485 guint8 tabval;
487 cmd = tvb_get_guint8(tvb, offset);
488 switch (cmd) {
490 case 0: /* IS */
491 proto_tree_add_text(tree, tvb, offset, 1, "Here's my %s", optname);
492 offset++;
493 len--;
494 break;
496 case 1: /* SEND */
497 proto_tree_add_text(tree, tvb, offset, 1, "Send your %s", optname);
498 offset++;
499 len--;
500 break;
502 default:
503 expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
504 offset++;
505 len--;
506 if (len > 0)
507 proto_tree_add_text(tree, tvb, offset, len, "Subcommand data");
508 return;
511 while (len > 0) {
512 tabval = tvb_get_guint8(tvb, offset);
513 switch (tabval) {
515 case 0:
516 proto_tree_add_text(tree, tvb, offset, 1,
517 "Sender wants to handle tab stops");
518 break;
520 default:
521 proto_tree_add_text(tree, tvb, offset, 1,
522 "Sender wants receiver to handle tab stop at %u",
523 tabval);
524 break;
526 case 251:
527 case 252:
528 case 253:
529 case 254:
530 proto_tree_add_text(tree, tvb, offset, 1,
531 "Invalid value: %u", tabval);
532 break;
534 case 255:
535 proto_tree_add_text(tree, tvb, offset, 1,
536 "Sender wants receiver to handle tab stops");
537 break;
539 offset++;
540 len--;
544 static void
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);
549 offset += 2;
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 */
571 static void
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[] = {
576 "Request",
577 "<invalid>",
578 "<invalid>",
579 "<invalid>",
580 "<invalid>",
581 "5",
582 "6",
583 "7",
586 static const char *parities[] = {
587 "Request",
588 "None",
589 "Odd",
590 "Even",
591 "Mark",
592 "Space"
594 static const char *stops[] = {
595 "Request",
596 "1",
597 "2",
598 "1.5"
600 static const char *control[] = {
601 "Output Flow Control Request",
602 "Output Flow: None",
603 "Output Flow: XON/XOFF",
604 "Output Flow: CTS/RTS",
605 "Break Request",
606 "Break: ON",
607 "Break: OFF",
608 "DTR Request",
609 "DTR: ON",
610 "DTR: OFF",
611 "RTS Request",
612 "RTS: ON",
613 "RTS: OFF",
614 "Input Flow Control Request",
615 "Input Flow: None",
616 "Input Flow: XON/XOFF",
617 "Input Flow: CTS/RTS",
618 "Output Flow: DCD",
619 "Input Flow: DTR",
620 "Output Flow: DSR"
622 static const char *linestate_bits[] = {
623 "Data Ready",
624 "Overrun Error",
625 "Parity Error",
626 "Framing Error",
627 "Break Detected",
628 "Transfer Holding Register Empty",
629 "Transfer Shift Register Empty",
630 "Timeout Error"
632 static const char *modemstate_bits[] = {
633 "DCTS",
634 "DDSR",
635 "TERI",
636 "DDCD",
637 "CTS",
638 "DSR",
639 "RI",
640 "DCD"
642 static const char *purges[] = {
643 "Purge None",
644 "Purge RX",
645 "Purge TX",
646 "Purge RX/TX"
649 guint8 cmd;
650 guint8 isservercmd;
651 const char *source;
653 cmd = tvb_get_guint8(tvb, offset);
654 isservercmd = cmd > 99;
655 cmd = (isservercmd) ? (cmd - 100) : cmd;
656 source = (isservercmd) ? "Server" : "Client";
657 switch (cmd) {
658 case TNCOMPORT_SIGNATURE:
659 len--;
660 if (len == 0) {
661 proto_tree_add_text(tree, tvb, offset, 1, "%s Requests Signature",source);
662 } else {
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);
667 break;
669 case TNCOMPORT_SETBAUDRATE:
670 len--;
671 if (len >= 4) {
672 guint32 baud = tvb_get_ntohl(tvb, offset+1);
673 if (baud == 0) {
674 proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_baud_rate, tvb, offset, 5, 0, "%s Requests Baud Rate",source);
675 } else {
676 proto_tree_add_uint_format_value(tree, hf_telnet_comport_subopt_baud_rate, tvb, offset, 5, baud, "%s Baud Rate: %d",source,baud);
678 } else {
679 expert_add_info_format(pinfo, item, &ei_telnet_invalid_baud_rate, "%s <Invalid Baud Rate Packet>", source);
681 break;
683 case TNCOMPORT_SETDATASIZE:
684 len--;
685 if (len >= 1) {
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);
690 } else {
691 expert_add_info_format(pinfo, item, &ei_telnet_invalid_data_size, "%s <Invalid Data Size Packet>", source);
693 break;
695 case TNCOMPORT_SETPARITY:
696 len--;
697 if (len >= 1) {
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);
702 } else {
703 expert_add_info_format(pinfo, item, &ei_telnet_invalid_parity, "%s <Invalid Parity Packet>", source);
705 break;
706 case TNCOMPORT_SETSTOPSIZE:
707 len--;
708 if (len >= 1) {
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);
713 } else {
714 expert_add_info_format(pinfo, item, &ei_telnet_invalid_stop, "%s <Invalid Stop Packet>", source);
716 break;
718 case TNCOMPORT_SETCONTROL:
719 len--;
720 if (len >= 1) {
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);
725 } else {
726 expert_add_info_format(pinfo, item, &ei_telnet_invalid_control, "%s <Invalid Control Packet>", source);
728 break;
730 case TNCOMPORT_SETLINESTATEMASK:
731 case TNCOMPORT_NOTIFYLINESTATE:
732 len--;
733 if (len >= 1) {
734 const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
735 "%s Set Linestate Mask: %s" : "%s Linestate: %s";
736 char ls_buffer[512];
737 guint8 ls = tvb_get_guint8(tvb, offset+1);
738 int print_count = 0;
739 int idx;
740 ls_buffer[0] = '\0';
741 for (idx = 0; idx < 8; idx++) {
742 int bit = ls & 1;
743 if (bit) {
744 if (print_count != 0) {
745 g_strlcat(ls_buffer,", ",512);
747 g_strlcat(ls_buffer,linestate_bits[idx], 512);
748 print_count++;
750 ls = ls >> 1;
752 proto_tree_add_text(tree, tvb, offset, 2, print_pattern, source, ls_buffer);
753 } else {
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);
758 break;
760 case TNCOMPORT_SETMODEMSTATEMASK:
761 case TNCOMPORT_NOTIFYMODEMSTATE:
762 len--;
763 if (len >= 1) {
764 const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
765 "%s Set Modemstate Mask: %s" : "%s Modemstate: %s";
766 char ms_buffer[256];
767 guint8 ms = tvb_get_guint8(tvb, offset+1);
768 int print_count = 0;
769 int idx;
770 ms_buffer[0] = '\0';
771 for (idx = 0; idx < 8; idx++) {
772 int bit = ms & 1;
773 if (bit) {
774 if (print_count != 0) {
775 g_strlcat(ms_buffer,", ",256);
777 g_strlcat(ms_buffer,modemstate_bits[idx],256);
778 print_count++;
780 ms = ms >> 1;
782 proto_tree_add_text(tree, tvb, offset, 2, print_pattern, source, ms_buffer);
783 } else {
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);
788 break;
790 case TNCOMPORT_FLOWCONTROLSUSPEND:
791 len--;
792 proto_tree_add_text(tree, tvb, offset, 1, "%s Flow Control Suspend",source);
793 break;
795 case TNCOMPORT_FLOWCONTROLRESUME:
796 len--;
797 proto_tree_add_text(tree, tvb, offset, 1, "%s Flow Control Resume",source);
798 break;
800 case TNCOMPORT_PURGEDATA:
801 len--;
802 if (len >= 1) {
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,
806 "%s %s",source,p);
807 } else {
808 expert_add_info_format(pinfo, item, &ei_telnet_invalid_purge, "%s <Invalid Purge Packet>", source);
810 break;
812 default:
813 expert_add_info_format(pinfo, item, &ei_telnet_invalid_subcommand, "Invalid %s subcommand %u", optname, cmd);
814 offset++;
815 len--;
816 if (len > 0)
817 proto_tree_add_text(tree, tvb, offset, len, "Subcommand data");
818 return;
823 static const value_string rfc_opt_vals[] = {
824 { 0, "OFF" },
825 { 1, "ON" },
826 { 2, "RESTART-ANY" },
827 { 3, "RESTART-XON" },
828 { 0, NULL }
831 static void
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);
838 #define TN_ENC_IS 0
839 #define TN_ENC_SUPPORT 1
840 #define TN_ENC_REPLY 2
841 #define TN_ENC_START 3
842 #define TN_ENC_END 4
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[] = {
848 { TN_ENC_IS, "IS" },
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" },
857 { 0, NULL }
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" },
879 { 0, NULL }
883 #define TN_AC_IS 0
884 #define TN_AC_SEND 1
885 #define TN_AC_REPLY 2
886 #define TN_AC_NAME 3
887 static const value_string auth_cmd_vals[] = {
888 { TN_AC_IS, "IS" },
889 { TN_AC_SEND, "SEND" },
890 { TN_AC_REPLY, "REPLY" },
891 { TN_AC_NAME, "NAME" },
892 { 0, NULL }
895 #define TN_AT_NULL 0
896 #define TN_AT_KRB4 1
897 #define TN_AT_KRB5 2
898 #define TN_AT_SPX 3
899 #define TN_AT_MINK 4
900 #define TN_AT_SRP 5
901 #define TN_AT_RSA 6
902 #define TN_AT_SSL 7
903 #define TN_AT_LOKI 10
904 #define TN_AT_SSA 11
905 #define TN_AT_KEA_SJ 12
906 #define TN_AT_KEA_SJ_INTEG 13
907 #define TN_AT_DSS 14
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" },
924 { 0, NULL }
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" },
947 { 0, NULL }
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" },
964 { 0, NULL }
966 static void
967 dissect_authentication_type_pair(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, proto_tree *tree)
969 guint8 type, mod;
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
984 static tvbuff_t *
985 unescape_and_tvbuffify_telnet_option(packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
987 tvbuff_t *krb5_tvb;
988 guint8 *buf;
989 const guint8 *spos;
990 guint8 *dpos;
991 int skip, l;
993 if(len>=MAX_KRB5_BLOB_LEN)
994 return NULL;
996 spos=tvb_get_ptr(tvb, offset, len);
997 buf=(guint8 *)g_malloc(len);
998 dpos=buf;
999 skip=0;
1000 l=len;
1001 while(l>0){
1002 if((spos[0]==0xff) && (spos[1]==0xff)){
1003 skip++;
1004 l-=2;
1005 *(dpos++)=0xff;
1006 spos+=2;
1007 continue;
1009 *(dpos++)=*(spos++);
1010 l--;
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");
1016 return krb5_tvb;
1020 /* as per RFC2942 */
1021 static void
1022 dissect_krb5_authentication_data(packet_info *pinfo, tvbuff_t *tvb, int offset, int len, proto_tree *tree, guint8 acmd)
1024 tvbuff_t *krb5_tvb;
1025 guint8 krb5_cmd;
1026 proto_item* ti;
1028 dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1029 offset+=2;
1030 len-=2;
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);
1035 offset++;
1036 len--;
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)){
1041 if(len){
1042 krb5_tvb=unescape_and_tvbuffify_telnet_option(pinfo, tvb, offset, len);
1043 if(krb5_tvb)
1044 dissect_kerberos_main(krb5_tvb, pinfo, tree, FALSE, NULL);
1045 else
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*/
1058 /*qqq*/
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)){
1063 if(len){
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 */
1083 static void
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_)
1087 guint8 acmd;
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
1091 kerberos v5
1093 acmd=tvb_get_guint8(tvb, offset);
1094 proto_tree_add_uint(tree, hf_telnet_auth_cmd, tvb, offset, 1, acmd);
1095 offset++;
1096 len--;
1098 switch(acmd){
1099 case TN_AC_REPLY:
1100 case TN_AC_IS:
1101 /* XXX here we shouldnt just assume it is krb5 */
1102 dissect_krb5_authentication_data(pinfo, tvb, offset, len, tree, acmd);
1103 break;
1104 case TN_AC_SEND:
1105 while(len>0){
1106 dissect_authentication_type_pair(pinfo, tvb, offset, tree);
1107 offset+=2;
1108 len-=2;
1110 break;
1111 case TN_AC_NAME:
1112 proto_tree_add_item(tree, hf_telnet_auth_name, tvb, offset, len, ENC_ASCII);
1113 break;
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) {
1119 guint8 etype;
1120 etype = tvb_get_guint8(tvb, offset);
1121 proto_tree_add_uint(tree, hf_telnet_enc_type, tvb, offset, 1, etype);
1124 static void
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);
1133 offset++;
1134 len--;
1136 switch(ecmd) {
1137 case TN_ENC_IS:
1138 case TN_ENC_REPLY:
1139 /* encryption type, type-specific data ... */
1140 if (len > 0) {
1141 dissect_encryption_type(tvb, offset, tree);
1142 offset++;
1143 len--;
1144 proto_tree_add_text(tree, tvb, offset, len, "Type-specific data");
1146 break;
1148 case TN_ENC_SUPPORT:
1149 /* list of encryption types ... */
1150 while (len > 0) {
1151 dissect_encryption_type(tvb, offset, tree);
1152 offset++;
1153 len--;
1155 break;
1157 case TN_ENC_START:
1158 /* keyid ... */
1159 if (len > 0) {
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");
1163 break;
1165 case TN_ENC_END:
1166 /* no data */
1167 break;
1169 case TN_ENC_REQUEST_START:
1170 /* (optional) keyid */
1171 if (len > 0)
1172 proto_tree_add_text(tree, tvb, offset, len, "Key ID (advisory)");
1173 break;
1175 case TN_ENC_REQUEST_END:
1176 /* no data */
1177 break;
1179 case TN_ENC_ENC_KEYID:
1180 case TN_ENC_DEC_KEYID:
1181 /* (optional) keyid - if not supplied, there are no more known keys */
1182 if (len > 0)
1183 proto_tree_add_text(tree, tvb, offset, len, "Key ID");
1184 break;
1186 default:
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 */
1195 NO_LENGTH,
1197 NULL
1200 "Echo", /* RFC 857 */
1201 NULL, /* no suboption negotiation */
1202 NO_LENGTH,
1204 NULL
1207 "Reconnection", /* DOD Protocol Handbook */
1208 NULL,
1209 NO_LENGTH,
1211 NULL
1214 "Suppress Go Ahead", /* RFC 858 */
1215 NULL, /* no suboption negotiation */
1216 NO_LENGTH,
1218 NULL
1221 "Approx Message Size Negotiation", /* Ethernet spec(!) */
1222 NULL,
1223 NO_LENGTH,
1225 NULL
1228 "Status", /* RFC 859 */
1229 &ett_status_subopt,
1230 VARIABLE_LENGTH,
1232 NULL /* XXX - fill me in */
1235 "Timing Mark", /* RFC 860 */
1236 NULL, /* no suboption negotiation */
1237 NO_LENGTH,
1239 NULL
1242 "Remote Controlled Trans and Echo", /* RFC 726 */
1243 &ett_rcte_subopt,
1244 VARIABLE_LENGTH,
1246 NULL /* XXX - fill me in */
1249 "Output Line Width", /* DOD Protocol Handbook */
1250 &ett_olw_subopt,
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 */
1257 &ett_ops_subopt,
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 */
1264 &ett_crdisp_subopt,
1265 FIXED_LENGTH,
1267 NULL /* XXX - fill me in */
1270 "Output Horizontal Tab Stops", /* RFC 653 */
1271 &ett_htstops_subopt,
1272 VARIABLE_LENGTH,
1274 dissect_htstops_subopt
1277 "Output Horizontal Tab Disposition", /* RFC 654 */
1278 &ett_htdisp_subopt,
1279 FIXED_LENGTH,
1281 NULL /* XXX - fill me in */
1284 "Output Formfeed Disposition", /* RFC 655 */
1285 &ett_ffdisp_subopt,
1286 FIXED_LENGTH,
1288 NULL /* XXX - fill me in */
1291 "Output Vertical Tabstops", /* RFC 656 */
1292 &ett_vtstops_subopt,
1293 VARIABLE_LENGTH,
1295 NULL /* XXX - fill me in */
1298 "Output Vertical Tab Disposition", /* RFC 657 */
1299 &ett_vtdisp_subopt,
1300 FIXED_LENGTH,
1302 NULL /* XXX - fill me in */
1305 "Output Linefeed Disposition", /* RFC 658 */
1306 &ett_lfdisp_subopt,
1307 FIXED_LENGTH,
1309 NULL /* XXX - fill me in */
1312 "Extended ASCII", /* RFC 698 */
1313 &ett_extasc_subopt,
1314 FIXED_LENGTH,
1316 NULL /* XXX - fill me in */
1319 "Logout", /* RFC 727 */
1320 NULL, /* no suboption negotiation */
1321 NO_LENGTH,
1323 NULL
1326 "Byte Macro", /* RFC 735 */
1327 &ett_bytemacro_subopt,
1328 VARIABLE_LENGTH,
1330 NULL /* XXX - fill me in */
1333 "Data Entry Terminal", /* RFC 732, RFC 1043 */
1334 &ett_det_subopt,
1335 VARIABLE_LENGTH,
1337 NULL /* XXX - fill me in */
1340 "SUPDUP", /* RFC 734, RFC 736 */
1341 NULL, /* no suboption negotiation */
1342 NO_LENGTH,
1344 NULL
1347 "SUPDUP Output", /* RFC 749 */
1348 &ett_supdupout_subopt,
1349 VARIABLE_LENGTH,
1351 NULL /* XXX - fill me in */
1354 "Send Location", /* RFC 779 */
1355 &ett_sendloc_subopt,
1356 VARIABLE_LENGTH,
1358 NULL /* XXX - fill me in */
1361 "Terminal Type", /* RFC 1091 */
1362 &ett_termtype_subopt,
1363 VARIABLE_LENGTH,
1365 dissect_string_subopt
1368 "End of Record", /* RFC 885 */
1369 NULL, /* no suboption negotiation */
1370 NO_LENGTH,
1372 NULL
1375 "TACACS User Identification", /* RFC 927 */
1376 &ett_tacacsui_subopt,
1377 FIXED_LENGTH,
1379 NULL /* XXX - fill me in */
1382 "Output Marking", /* RFC 933 */
1383 &ett_outmark_subopt,
1384 VARIABLE_LENGTH,
1386 dissect_outmark_subopt,
1389 "Terminal Location Number", /* RFC 946 */
1390 &ett_tlocnum_subopt,
1391 VARIABLE_LENGTH,
1393 NULL /* XXX - fill me in */
1396 "Telnet 3270 Regime", /* RFC 1041 */
1397 &ett_tn3270reg_subopt,
1398 VARIABLE_LENGTH,
1400 dissect_tn3270_regime_subopt
1403 "X.3 PAD", /* RFC 1053 */
1404 &ett_x3pad_subopt,
1405 VARIABLE_LENGTH,
1407 NULL /* XXX - fill me in */
1410 "Negotiate About Window Size", /* RFC 1073, DW183 */
1411 &ett_naws_subopt,
1412 FIXED_LENGTH,
1414 dissect_naws_subopt
1417 "Terminal Speed", /* RFC 1079 */
1418 &ett_tspeed_subopt,
1419 VARIABLE_LENGTH,
1421 NULL /* XXX - fill me in */
1424 "Remote Flow Control", /* RFC 1372 */
1425 &ett_rfc_subopt,
1426 FIXED_LENGTH,
1428 dissect_rfc_subopt
1431 "Linemode", /* RFC 1184 */
1432 &ett_linemode_subopt,
1433 VARIABLE_LENGTH,
1435 NULL /* XXX - fill me in */
1438 "X Display Location", /* RFC 1096 */
1439 &ett_xdpyloc_subopt,
1440 VARIABLE_LENGTH,
1442 dissect_string_subopt
1445 "Environment Option", /* RFC 1408, RFC 1571 */
1446 &ett_env_subopt,
1447 VARIABLE_LENGTH,
1449 NULL /* XXX - fill me in */
1452 "Authentication Option", /* RFC 2941 */
1453 &ett_auth_subopt,
1454 VARIABLE_LENGTH,
1456 dissect_authentication_subopt
1459 "Encryption Option", /* RFC 2946 */
1460 &ett_enc_subopt,
1461 VARIABLE_LENGTH,
1463 dissect_encryption_subopt
1466 "New Environment Option", /* RFC 1572 */
1467 &ett_newenv_subopt,
1468 VARIABLE_LENGTH,
1470 NULL /* XXX - fill me in */
1473 "TN3270E", /* RFC 1647 */
1474 &ett_tn3270e_subopt,
1475 VARIABLE_LENGTH,
1477 dissect_tn3270e_subopt
1480 "XAUTH", /* XAUTH */
1481 &ett_xauth_subopt,
1482 VARIABLE_LENGTH,
1484 NULL /* XXX - fill me in */
1487 "CHARSET", /* CHARSET */
1488 &ett_charset_subopt,
1489 VARIABLE_LENGTH,
1491 NULL /* XXX - fill me in */
1494 "Remote Serial Port", /* Remote Serial Port */
1495 &ett_rsp_subopt,
1496 VARIABLE_LENGTH,
1498 NULL /* XXX - fill me in */
1501 "COM Port Control", /* RFC 2217 */
1502 &ett_comport_subopt,
1503 VARIABLE_LENGTH,
1505 dissect_comport_subopt
1510 #define NOPTIONS array_length(options)
1512 static int
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;
1516 guint8 opt_byte;
1517 int subneg_len;
1518 const char *opt;
1519 int iac_offset;
1520 guint len;
1521 tvbuff_t *unescaped_tvb;
1522 void (*dissect)(packet_info *, const char *, tvbuff_t *, int, int, proto_tree *, proto_item*);
1523 gint cur_offset;
1524 gboolean iac_found;
1527 * As data with value iac (0xff) is possible, this value must be escaped
1528 * with iac (rfc 854).
1530 int iac_data = 0;
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>";
1538 dissect = NULL;
1539 } else {
1540 opt = options[opt_byte].name;
1541 dissect = options[opt_byte].dissect;
1543 offset++;
1545 /* Search for an unescaped IAC. */
1546 cur_offset = offset;
1547 len = tvb_length_remaining(tvb, offset);
1548 do {
1549 iac_offset = tvb_find_guint8(tvb, cur_offset, len, TN_IAC);
1550 iac_found = TRUE;
1551 if (iac_offset == -1) {
1552 /* None found - run to the end of the packet. */
1553 offset += len;
1554 } else {
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;
1559 } else {
1561 * We saw an escaped IAC, so we have to move ahead to the
1562 * next section
1564 iac_found = FALSE;
1565 cur_offset = iac_offset + 2;
1566 iac_data += 1;
1570 } while (!iac_found);
1572 subneg_len = offset - start_offset;
1574 start_offset += 3; /* skip IAC, SB, and option code */
1575 subneg_len -= 3;
1577 if (subneg_len > 0) {
1579 /* Now dissect the suboption parameters. */
1580 if (dissect != NULL) {
1582 switch (options[opt_byte].len_type) {
1584 case NO_LENGTH:
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");
1587 return offset;
1589 case FIXED_LENGTH:
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);
1593 return offset;
1595 break;
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);
1601 return offset;
1603 break;
1606 /* We have a dissector for this suboption's parameters; call it. */
1607 if (iac_data > 0) {
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);
1611 } else {
1612 (*dissect)(pinfo, opt, tvb, start_offset, subneg_len, option_tree, option_item);
1614 } else {
1615 /* We don't have a dissector for them; just show them as data. */
1616 if (iac_data > 0) {
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,
1620 "Option data");
1621 } else {
1622 proto_tree_add_text(option_tree, tvb, start_offset, subneg_len,
1623 "Option data");
1627 return offset;
1630 static void
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)
1634 guint8 opt_byte;
1635 const char *opt;
1636 gint ett = ett_telnet_subopt;
1638 opt_byte = tvb_get_guint8(tvb, *offset);
1639 if (opt_byte >= NOPTIONS) {
1640 opt = "<unknown option>";
1642 else {
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);
1650 (*offset)++;
1651 (*optname) = wmem_strdup_printf(wmem_packet_scope(), "%s %s", type, opt);
1654 static int
1655 telnet_command(packet_info *pinfo, proto_tree *telnet_tree, tvbuff_t *tvb, int start_offset)
1657 int offset = start_offset;
1658 guchar optcode;
1659 gchar* optname;
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);
1669 offset++;
1671 switch(optcode) {
1672 case TN_WILL:
1673 telnet_suboption_name(cmd_tree, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Will");
1674 break;
1676 case TN_WONT:
1677 telnet_suboption_name(cmd_tree, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Won't");
1678 break;
1680 case TN_DO:
1681 telnet_suboption_name(cmd_tree, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Do");
1682 break;
1684 case TN_DONT:
1685 telnet_suboption_name(cmd_tree, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Don't");
1686 break;
1688 case TN_SB:
1689 telnet_suboption_name(cmd_tree, tvb, &offset, &optname, &subopt_tree, &subopt_item, "Suboption");
1690 break;
1692 default:
1693 optname = (gchar*)val_to_str_const(optcode, cmd_vals, "<unknown option>");
1694 break;
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);
1705 return offset;
1708 static void
1709 telnet_add_text(proto_tree *tree, tvbuff_t *tvb, int offset, int len)
1711 gint next_offset;
1712 int linelen;
1713 guint8 c;
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
1732 * CR.
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
1736 * a line.
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 */
1743 len--;
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.
1749 break;
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))
1776 iac_offset+=2;
1777 len = tvb_length_remaining(tvb, iac_offset);
1779 return iac_offset;
1782 static void
1783 dissect_telnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1785 proto_tree *telnet_tree, *ti;
1786 tvbuff_t *next_tvb;
1787 gint offset = 0;
1788 guint len = 0;
1789 guint is_tn3270 = 0;
1790 guint is_tn5250 = 0;
1791 int data_len;
1792 gint iac_offset;
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;
1815 if (data_len > 0) {
1816 if (is_tn3270) {
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);
1822 } else
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);
1829 } else {
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;
1834 return;
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);
1842 break;
1847 void
1848 proto_register_telnet(void)
1850 static hf_register_info hf[] = {
1851 { &hf_telnet_cmd,
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 }
1951 { &hf_telnet_data,
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 }
1963 { &hf_tn3270_is,
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[] = {
1985 &ett_telnet,
1986 &ett_telnet_cmd,
1987 &ett_telnet_subopt,
1988 &ett_status_subopt,
1989 &ett_rcte_subopt,
1990 &ett_olw_subopt,
1991 &ett_ops_subopt,
1992 &ett_crdisp_subopt,
1993 &ett_htstops_subopt,
1994 &ett_htdisp_subopt,
1995 &ett_ffdisp_subopt,
1996 &ett_vtstops_subopt,
1997 &ett_vtdisp_subopt,
1998 &ett_lfdisp_subopt,
1999 &ett_extasc_subopt,
2000 &ett_bytemacro_subopt,
2001 &ett_det_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,
2009 &ett_x3pad_subopt,
2010 &ett_naws_subopt,
2011 &ett_tspeed_subopt,
2012 &ett_rfc_subopt,
2013 &ett_linemode_subopt,
2014 &ett_xdpyloc_subopt,
2015 &ett_env_subopt,
2016 &ett_auth_subopt,
2017 &ett_enc_subopt,
2018 &ett_newenv_subopt,
2019 &ett_tn3270e_subopt,
2020 &ett_xauth_subopt,
2021 &ett_charset_subopt,
2022 &ett_rsp_subopt,
2023 &ett_comport_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);
2053 void
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");