2 * Routines for telnet packet dissection
3 * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
5 * $Id: packet-telnet.c,v 1.17 2000/09/29 19:06:12 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.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.
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
47 static int proto_telnet = -1;
49 static gint ett_telnet = -1;
50 static gint ett_telnet_subopt = -1;
52 /* Some defines for Telnet */
54 #define TCP_PORT_TELNET 23
77 static const char *options[] = {
78 "Binary Transmission",
82 "Approx Message Size Negotiation",
85 "Remote Controlled Trans and Echo",
88 "Output Carriage-Return Disposition",
89 "Output Horizontal Tab Stops",
90 "Output Horizontal Tab Disposition",
91 "Output Formfeed Disposition",
92 "Output Vertical Tabstops",
93 "Output Vertical Tab Disposition",
94 "Output Linefeed Disposition",
98 "Data Entry Terminal",
104 "TACACS User Identification",
106 "Terminal Location Number",
107 "Telnet 3270 Regime",
109 "Negotiate About Window Size",
111 "Remote Flow Control",
113 "X Display Location",
114 "Environment Option",
115 "Authentication Option",
117 "New Environment Option",
121 #define NOPTIONS (sizeof options / sizeof options[0])
124 telnet_sub_option(proto_tree *telnet_tree, const u_char *pd,
127 proto_tree *ti, *option_tree;
128 int offset = start_offset;
130 gboolean not_found = TRUE;
133 offset += 2; /* skip IAC and SB */
135 /* Figure out the option and type */
136 if (pd[offset] > NOPTIONS)
137 opt = "<unknown option>";
139 opt = options[pd[offset]];
144 while (offset < pi.captured_len && not_found) {
145 if (pd[offset] == TN_IAC)
151 subneg_len = offset - start_offset;
153 ti = proto_tree_add_text(telnet_tree, NullTVB, start_offset, subneg_len,
154 "Suboption Begin: %s", opt);
156 option_tree = proto_item_add_subtree(ti, ett_telnet_subopt);
158 proto_tree_add_text(option_tree, NullTVB, start_offset + 2, 2,
159 "%s %s", (req ? "Send your" : "Here's my"), opt);
161 if (req == 0) { /* Add the value */
162 proto_tree_add_text(option_tree, NullTVB, start_offset + 4, subneg_len - 4,
163 "Value: %s", format_text(&pd[start_offset + 4], subneg_len - 4));
169 telnet_will_wont_do_dont(proto_tree *telnet_tree, const u_char *pd,
170 int start_offset, char *type)
172 int offset = start_offset;
175 offset += 2; /* skip IAC and WILL,WONT,DO,DONT} */
176 if (pd[offset] > NOPTIONS)
177 opt = "<unknown option>";
179 opt = options[pd[offset]];
182 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 3,
183 "Command: %s %s", type, opt);
188 telnet_command(proto_tree *telnet_tree, const u_char *pd, int start_offset)
190 int offset = start_offset;
193 offset += 1; /* skip IAC */
194 optcode = pd[offset];
199 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
200 "Command: End of File");
204 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
205 "Command: Suspend Current Process");
209 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
210 "Command: Abort Process");
214 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
215 "Command: End of Record");
219 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
220 "Command: Suboption End");
224 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
225 "Command: No Operation");
229 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
230 "Command: Data Mark");
234 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
239 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
240 "Command: Interrupt Process");
244 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
245 "Command: Abort Output");
249 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
250 "Command: Are You There?");
254 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
255 "Command: Escape Character");
259 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
260 "Command: Erase Line");
264 proto_tree_add_text(telnet_tree, NullTVB, start_offset, 2,
265 "Command: Go Ahead");
269 offset = telnet_sub_option(telnet_tree, pd, start_offset);
273 offset = telnet_will_wont_do_dont(telnet_tree, pd, start_offset,
278 offset = telnet_will_wont_do_dont(telnet_tree, pd, start_offset,
283 offset = telnet_will_wont_do_dont(telnet_tree, pd, start_offset,
288 offset = telnet_will_wont_do_dont(telnet_tree, pd, start_offset,
297 telnet_add_text(proto_tree *tree, tvbuff_t *tvb, const u_char *pd,
300 const u_char *data, *dataend;
301 const u_char *lineend, *eol;
305 dataend = data + len;
306 while (data < dataend) {
308 * Find the end of the line.
310 lineend = find_line_end(data, dataend, &eol);
311 linelen = lineend - data;
313 proto_tree_add_text(tree, NullTVB, offset, linelen,
314 "Data: %s", format_text(data, linelen));
321 dissect_telnet(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
323 proto_tree *telnet_tree, *ti;
325 OLD_CHECK_DISPLAY_AS_DATA(proto_telnet, pd, offset, fd, tree);
327 if (check_col(fd, COL_PROTOCOL))
328 col_add_str(fd, COL_PROTOCOL, "TELNET");
330 if (check_col(fd, COL_INFO))
331 col_add_fstr(fd, COL_INFO, "Telnet Data ...");
337 ti = proto_tree_add_item(tree, proto_telnet, NullTVB, offset, END_OF_FRAME, FALSE);
338 telnet_tree = proto_item_add_subtree(ti, ett_telnet);
340 data_offset = offset;
344 * Scan through the buffer looking for an IAC byte.
346 while (offset < pi.captured_len) {
347 if (pd[offset] == TN_IAC) {
349 * We found an IAC byte.
350 * If there's any data before it, add that data to the
351 * tree, a line at a time.
354 telnet_add_text(telnet_tree, NullTVB, pd, data_offset, data_len);
356 data_offset = offset;
360 * Now interpret the command.
362 offset = telnet_command(telnet_tree, pd, offset);
363 data_offset = offset;
372 * We've reached the end of the buffer.
373 * If there's any data left, add it to the tree.
376 telnet_add_text(telnet_tree, NullTVB, pd, data_offset, data_len);
381 proto_register_telnet(void)
383 /* static hf_register_info hf[] = {
385 { "Name", "telnet.abbreviation", TYPE, VALS_POINTER }},
387 static gint *ett[] = {
392 proto_telnet = proto_register_protocol("Telnet", "telnet");
393 /* proto_register_field_array(proto_telnet, hf, array_length(hf));*/
394 proto_register_subtree_array(ett, array_length(ett));
398 proto_reg_handoff_telnet(void)
400 old_dissector_add("tcp.port", TCP_PORT_TELNET, dissect_telnet);