1999-08-18 00:57:54 +00:00
|
|
|
/* packet-telnet.c
|
2003-02-24 01:04:30 +00:00
|
|
|
* Routines for Telnet packet dissection; see RFC 854 and RFC 855
|
1999-04-05 21:54:41 +00:00
|
|
|
* Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
|
|
|
|
*
|
Add new routines:
tvb_get_string() - takes a tvbuff, an offset, and a length as
arguments, allocates a buffer big enough to hold a string with
the specified number of bytes plus an added null terminator
(i.e., length+1), copies the specified number of bytes from the
tvbuff, at the specified offset, to that buffer and puts in a
null terminator, and returns a pointer to that buffer (or throws
an exception before allocating the buffer if that many bytes
aren't available in the tvbuff);
tvb_get_stringz() - takes a tvbuff, an offset, and a pointer to
a "gint" as arguments, gets the size of the null-terminated
string starting at the specified offset in the tvbuff (throwing
an exception if the null terminator isn't found), allocates a
buffer big enough to hold that string, copies the string to that
buffer, and returns a pointer to that buffer and stores the
length of the string (including the terminating null) in the
variable pointed to by the "gint" pointer.
Replace many pieces of code allocating a buffer and copying a string
with calls to "tvb_get_string()" (for one thing, "tvb_get_string()"
doesn't require you to remember that the argument to
"tvb_get_nstringz0()" is the size of the buffer into which you're
copying the string, which might be the length of the string to be copied
*plus 1*).
Don't use fixed-length buffers for null-terminated strings (even if the
code that generates those packets has a #define to limit the length of
the string). Use "tvb_get_stringz()", instead.
In some cases where a value is fetched but is only used to pass an
argument to a "proto_tree_add_XXX" routine, use "proto_tree_add_item()"
instead.
svn path=/trunk/; revision=7859
2003-06-12 08:33:32 +00:00
|
|
|
* $Id: packet-telnet.c,v 1.41 2003/06/12 08:33:30 guy Exp $
|
1999-04-05 21:54:41 +00:00
|
|
|
*
|
|
|
|
* Ethereal - Network traffic analyzer
|
2001-12-03 04:00:26 +00:00
|
|
|
* By Gerald Combs <gerald@ethereal.com>
|
1999-04-05 21:54:41 +00:00
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
|
|
|
* Copied from packet-pop.c
|
2002-08-28 21:04:11 +00:00
|
|
|
*
|
1999-04-05 21:54:41 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2002-08-28 21:04:11 +00:00
|
|
|
*
|
1999-04-05 21:54:41 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2002-08-28 21:04:11 +00:00
|
|
|
*
|
1999-04-05 21:54:41 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <glib.h>
|
2002-01-21 07:37:49 +00:00
|
|
|
#include <epan/packet.h>
|
|
|
|
#include <epan/strutil.h>
|
1999-04-05 21:54:41 +00:00
|
|
|
|
1999-07-29 05:47:07 +00:00
|
|
|
static int proto_telnet = -1;
|
|
|
|
|
1999-11-16 11:44:20 +00:00
|
|
|
static gint ett_telnet = -1;
|
|
|
|
static gint ett_telnet_subopt = -1;
|
2003-02-24 01:04:30 +00:00
|
|
|
static gint ett_status_subopt = -1;
|
|
|
|
static gint ett_rcte_subopt = -1;
|
|
|
|
static gint ett_olw_subopt = -1;
|
|
|
|
static gint ett_ops_subopt = -1;
|
|
|
|
static gint ett_crdisp_subopt = -1;
|
|
|
|
static gint ett_htstops_subopt = -1;
|
|
|
|
static gint ett_htdisp_subopt = -1;
|
|
|
|
static gint ett_ffdisp_subopt = -1;
|
|
|
|
static gint ett_vtstops_subopt = -1;
|
|
|
|
static gint ett_vtdisp_subopt = -1;
|
|
|
|
static gint ett_lfdisp_subopt = -1;
|
|
|
|
static gint ett_extasc_subopt = -1;
|
|
|
|
static gint ett_bytemacro_subopt = -1;
|
|
|
|
static gint ett_det_subopt = -1;
|
|
|
|
static gint ett_supdupout_subopt = -1;
|
|
|
|
static gint ett_sendloc_subopt = -1;
|
|
|
|
static gint ett_termtype_subopt = -1;
|
|
|
|
static gint ett_tacacsui_subopt = -1;
|
|
|
|
static gint ett_outmark_subopt = -1;
|
|
|
|
static gint ett_tlocnum_subopt = -1;
|
|
|
|
static gint ett_tn3270reg_subopt = -1;
|
|
|
|
static gint ett_x3pad_subopt = -1;
|
|
|
|
static gint ett_naws_subopt = -1;
|
|
|
|
static gint ett_tspeed_subopt = -1;
|
|
|
|
static gint ett_rfc_subopt = -1;
|
|
|
|
static gint ett_linemode_subopt = -1;
|
|
|
|
static gint ett_xdpyloc_subopt = -1;
|
|
|
|
static gint ett_env_subopt = -1;
|
|
|
|
static gint ett_auth_subopt = -1;
|
|
|
|
static gint ett_enc_subopt = -1;
|
|
|
|
static gint ett_newenv_subopt = -1;
|
|
|
|
static gint ett_tn3270e_subopt = -1;
|
2003-04-22 19:57:33 +00:00
|
|
|
static gint ett_xauth_subopt = -1;
|
|
|
|
static gint ett_charset_subopt = -1;
|
|
|
|
static gint ett_rsp_subopt = -1;
|
|
|
|
static gint ett_comport_subopt = -1;
|
|
|
|
|
1999-11-16 11:44:20 +00:00
|
|
|
|
1999-04-05 21:54:41 +00:00
|
|
|
/* Some defines for Telnet */
|
|
|
|
|
2000-04-08 07:07:42 +00:00
|
|
|
#define TCP_PORT_TELNET 23
|
|
|
|
|
1999-04-05 21:54:41 +00:00
|
|
|
#define TN_IAC 255
|
|
|
|
#define TN_DONT 254
|
|
|
|
#define TN_DO 253
|
|
|
|
#define TN_WONT 252
|
|
|
|
#define TN_WILL 251
|
|
|
|
#define TN_SB 250
|
|
|
|
#define TN_GA 249
|
|
|
|
#define TN_EL 248
|
|
|
|
#define TN_EC 247
|
|
|
|
#define TN_AYT 246
|
|
|
|
#define TN_AO 245
|
|
|
|
#define TN_IP 244
|
|
|
|
#define TN_BRK 243
|
|
|
|
#define TN_DM 242
|
|
|
|
#define TN_NOP 241
|
|
|
|
#define TN_SE 240
|
|
|
|
#define TN_EOR 239
|
|
|
|
#define TN_ABORT 238
|
|
|
|
#define TN_SUSP 237
|
|
|
|
#define TN_EOF 236
|
|
|
|
|
2003-04-22 19:57:33 +00:00
|
|
|
|
2003-02-24 01:04:30 +00:00
|
|
|
typedef enum {
|
|
|
|
NO_LENGTH, /* option has no data, hence no length */
|
|
|
|
FIXED_LENGTH, /* option always has the same length */
|
|
|
|
VARIABLE_LENGTH /* option is variable-length - optlen is minimum */
|
|
|
|
} tn_opt_len_type;
|
|
|
|
|
|
|
|
/* Member of table of IP or TCP options. */
|
|
|
|
typedef struct tn_opt {
|
|
|
|
char *name; /* name of option */
|
|
|
|
gint *subtree_index; /* pointer to subtree index for option */
|
|
|
|
tn_opt_len_type len_type; /* type of option length field */
|
|
|
|
int optlen; /* value length should be (minimum if VARIABLE) */
|
|
|
|
void (*dissect)(const char *, tvbuff_t *, int, int, proto_tree *);
|
|
|
|
/* routine to dissect option */
|
|
|
|
} tn_opt;
|
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_string_subopt(const char *optname, tvbuff_t *tvb, int offset, int len,
|
|
|
|
proto_tree *tree)
|
|
|
|
{
|
|
|
|
guint8 cmd;
|
|
|
|
|
|
|
|
cmd = tvb_get_guint8(tvb, offset);
|
|
|
|
switch (cmd) {
|
|
|
|
|
|
|
|
case 0: /* IS */
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Here's my %s", optname);
|
|
|
|
offset++;
|
|
|
|
len--;
|
|
|
|
if (len > 0) {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, len, "Value: %s",
|
|
|
|
tvb_format_text(tvb, offset, len));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: /* SEND */
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Send your %s", optname);
|
|
|
|
offset++;
|
|
|
|
len--;
|
|
|
|
if (len > 0)
|
|
|
|
proto_tree_add_text(tree, tvb, offset, len, "Extra data");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Invalid %s subcommand %u",
|
|
|
|
optname, cmd);
|
|
|
|
offset++;
|
|
|
|
len--;
|
|
|
|
if (len > 0)
|
|
|
|
proto_tree_add_text(tree, tvb, offset, len, "Subcommand data");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_outmark_subopt(const char *optname _U_, tvbuff_t *tvb, int offset,
|
|
|
|
int len, proto_tree *tree)
|
|
|
|
{
|
|
|
|
guint8 cmd;
|
|
|
|
int gs_offset, datalen;
|
|
|
|
|
|
|
|
while (len > 0) {
|
|
|
|
cmd = tvb_get_guint8(tvb, offset);
|
|
|
|
switch (cmd) {
|
|
|
|
|
|
|
|
case 6: /* ACK */
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "ACK");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 21: /* NAK */
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "NAK");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'D':
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Default");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'T':
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Top");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B':
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Bottom");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'L':
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Left");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'R':
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Right");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Bogus value: %u", cmd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
offset++;
|
|
|
|
len--;
|
|
|
|
|
|
|
|
/* Look for a GS */
|
|
|
|
gs_offset = tvb_find_guint8(tvb, offset, len, 29);
|
|
|
|
if (gs_offset == -1) {
|
|
|
|
/* None found - run to the end of the packet. */
|
|
|
|
gs_offset = offset + len;
|
|
|
|
}
|
|
|
|
datalen = gs_offset - offset;
|
|
|
|
if (datalen > 0) {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, datalen, "Banner: %s",
|
|
|
|
tvb_format_text(tvb, offset, datalen));
|
|
|
|
offset += datalen;
|
|
|
|
len -= datalen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_htstops_subopt(const char *optname, tvbuff_t *tvb, int offset, int len,
|
|
|
|
proto_tree *tree)
|
|
|
|
{
|
|
|
|
guint8 cmd;
|
|
|
|
guint8 tabval;
|
|
|
|
|
|
|
|
cmd = tvb_get_guint8(tvb, offset);
|
|
|
|
switch (cmd) {
|
|
|
|
|
|
|
|
case 0: /* IS */
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Here's my %s", optname);
|
|
|
|
offset++;
|
|
|
|
len--;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: /* SEND */
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Send your %s", optname);
|
|
|
|
offset++;
|
|
|
|
len--;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Invalid %s subcommand %u",
|
|
|
|
optname, cmd);
|
|
|
|
offset++;
|
|
|
|
len--;
|
|
|
|
if (len > 0)
|
|
|
|
proto_tree_add_text(tree, tvb, offset, len, "Subcommand data");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (len > 0) {
|
|
|
|
tabval = tvb_get_guint8(tvb, offset);
|
|
|
|
switch (tabval) {
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1,
|
|
|
|
"Sender wants to handle tab stops");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1,
|
|
|
|
"Sender wants receiver to handle tab stop at %u",
|
|
|
|
tabval);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 251:
|
|
|
|
case 252:
|
|
|
|
case 253:
|
|
|
|
case 254:
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1,
|
|
|
|
"Invalid value: %u", tabval);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 255:
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1,
|
|
|
|
"Sender wants receiver to handle tab stops");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
offset++;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_naws_subopt(const char *optname _U_, tvbuff_t *tvb, int offset,
|
|
|
|
int len _U_, proto_tree *tree)
|
|
|
|
{
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, "Width: %u",
|
|
|
|
tvb_get_ntohs(tvb, offset));
|
|
|
|
offset += 2;
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, "Height: %u",
|
|
|
|
tvb_get_ntohs(tvb, offset));
|
|
|
|
}
|
|
|
|
|
2003-04-22 20:35:49 +00:00
|
|
|
/* BEGIN RFC-2217 (COM Port Control) Definitions */
|
2003-04-22 19:57:33 +00:00
|
|
|
|
|
|
|
#define TNCOMPORT_SIGNATURE 0
|
|
|
|
#define TNCOMPORT_SETBAUDRATE 1
|
|
|
|
#define TNCOMPORT_SETDATASIZE 2
|
|
|
|
#define TNCOMPORT_SETPARITY 3
|
|
|
|
#define TNCOMPORT_SETSTOPSIZE 4
|
|
|
|
#define TNCOMPORT_SETCONTROL 5
|
|
|
|
#define TNCOMPORT_NOTIFYLINESTATE 6
|
|
|
|
#define TNCOMPORT_NOTIFYMODEMSTATE 7
|
|
|
|
#define TNCOMPORT_FLOWCONTROLSUSPEND 8
|
|
|
|
#define TNCOMPORT_FLOWCONTROLRESUME 9
|
|
|
|
#define TNCOMPORT_SETLINESTATEMASK 10
|
|
|
|
#define TNCOMPORT_SETMODEMSTATEMASK 11
|
|
|
|
#define TNCOMPORT_PURGEDATA 12
|
|
|
|
|
2003-04-22 20:35:49 +00:00
|
|
|
/* END RFC-2217 (COM Port Control) Definitions */
|
2003-04-22 19:57:33 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_comport_subopt(const char *optname, tvbuff_t *tvb, int offset, int len,
|
|
|
|
proto_tree *tree)
|
|
|
|
{static const char *datasizes[] = {
|
|
|
|
"Request",
|
|
|
|
"<invalid>",
|
|
|
|
"<invalid>",
|
|
|
|
"<invalid>",
|
|
|
|
"<invalid>",
|
|
|
|
"5",
|
|
|
|
"6",
|
|
|
|
"7",
|
|
|
|
"8"
|
|
|
|
};
|
|
|
|
static const char *parities[] = {
|
|
|
|
"Request",
|
|
|
|
"None",
|
|
|
|
"Odd",
|
|
|
|
"Even",
|
|
|
|
"Mark",
|
|
|
|
"Space"
|
|
|
|
};
|
|
|
|
static const char *stops[] = {
|
|
|
|
"Request",
|
|
|
|
"1",
|
|
|
|
"2",
|
|
|
|
"1.5"
|
|
|
|
};
|
|
|
|
static const char *control[] = {
|
|
|
|
"Output Flow Control Request",
|
|
|
|
"Output Flow: None",
|
|
|
|
"Output Flow: XON/XOFF",
|
|
|
|
"Output Flow: CTS/RTS",
|
|
|
|
"Break Request",
|
|
|
|
"Break: ON",
|
|
|
|
"Break: OFF",
|
|
|
|
"DTR Request",
|
|
|
|
"DTR: ON",
|
|
|
|
"DTR: OFF",
|
|
|
|
"RTS Request",
|
|
|
|
"RTS: ON",
|
|
|
|
"RTS: OFF",
|
|
|
|
"Input Flow Control Request",
|
|
|
|
"Input Flow: None",
|
|
|
|
"Input Flow: XON/XOFF",
|
|
|
|
"Input Flow: CTS/RTS",
|
|
|
|
"Output Flow: DCD",
|
|
|
|
"Input Flow: DTR",
|
|
|
|
"Output Flow: DSR"
|
|
|
|
};
|
|
|
|
static const char *linestate_bits[] = {
|
|
|
|
"Data Ready",
|
|
|
|
"Overrun Error",
|
|
|
|
"Parity Error",
|
|
|
|
"Framing Error",
|
|
|
|
"Break Detected",
|
|
|
|
"Transfer Holding Register Empty",
|
|
|
|
"Transfer Shift Register Empty",
|
|
|
|
"Timeout Error"
|
|
|
|
};
|
|
|
|
static const char *modemstate_bits[] = {
|
|
|
|
"DCTS",
|
|
|
|
"DDSR",
|
|
|
|
"TERI",
|
|
|
|
"DDCD",
|
|
|
|
"CTS",
|
|
|
|
"DSR",
|
|
|
|
"RI",
|
|
|
|
"DCD"
|
|
|
|
};
|
|
|
|
static const char *purges[] = {
|
|
|
|
"Purge None",
|
|
|
|
"Purge RX",
|
|
|
|
"Purge TX",
|
|
|
|
"Purge RX/TX"
|
|
|
|
};
|
|
|
|
|
|
|
|
guint8 cmd;
|
|
|
|
guint8 isservercmd;
|
|
|
|
char *source;
|
|
|
|
|
|
|
|
cmd = tvb_get_guint8(tvb, offset);
|
|
|
|
isservercmd = cmd > 99;
|
|
|
|
cmd = (isservercmd) ? (cmd - 100) : cmd;
|
|
|
|
source = (isservercmd) ? "Server" : "Client";
|
|
|
|
switch (cmd) {
|
|
|
|
|
|
|
|
case TNCOMPORT_SIGNATURE:
|
|
|
|
len--;
|
|
|
|
if (len == 0) {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "%s Requests Signature",source);
|
|
|
|
} else {
|
Add new routines:
tvb_get_string() - takes a tvbuff, an offset, and a length as
arguments, allocates a buffer big enough to hold a string with
the specified number of bytes plus an added null terminator
(i.e., length+1), copies the specified number of bytes from the
tvbuff, at the specified offset, to that buffer and puts in a
null terminator, and returns a pointer to that buffer (or throws
an exception before allocating the buffer if that many bytes
aren't available in the tvbuff);
tvb_get_stringz() - takes a tvbuff, an offset, and a pointer to
a "gint" as arguments, gets the size of the null-terminated
string starting at the specified offset in the tvbuff (throwing
an exception if the null terminator isn't found), allocates a
buffer big enough to hold that string, copies the string to that
buffer, and returns a pointer to that buffer and stores the
length of the string (including the terminating null) in the
variable pointed to by the "gint" pointer.
Replace many pieces of code allocating a buffer and copying a string
with calls to "tvb_get_string()" (for one thing, "tvb_get_string()"
doesn't require you to remember that the argument to
"tvb_get_nstringz0()" is the size of the buffer into which you're
copying the string, which might be the length of the string to be copied
*plus 1*).
Don't use fixed-length buffers for null-terminated strings (even if the
code that generates those packets has a #define to limit the length of
the string). Use "tvb_get_stringz()", instead.
In some cases where a value is fetched but is only used to pass an
argument to a "proto_tree_add_XXX" routine, use "proto_tree_add_item()"
instead.
svn path=/trunk/; revision=7859
2003-06-12 08:33:32 +00:00
|
|
|
guint8 *sig = tvb_get_string(tvb, offset + 1, len);
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1 + len, "%s Signature: %s",source, sig);
|
2003-04-30 02:35:28 +00:00
|
|
|
g_free(sig);
|
2003-04-22 19:57:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_SETBAUDRATE:
|
|
|
|
len--;
|
|
|
|
if (len >= 4) {
|
Add new routines:
tvb_get_string() - takes a tvbuff, an offset, and a length as
arguments, allocates a buffer big enough to hold a string with
the specified number of bytes plus an added null terminator
(i.e., length+1), copies the specified number of bytes from the
tvbuff, at the specified offset, to that buffer and puts in a
null terminator, and returns a pointer to that buffer (or throws
an exception before allocating the buffer if that many bytes
aren't available in the tvbuff);
tvb_get_stringz() - takes a tvbuff, an offset, and a pointer to
a "gint" as arguments, gets the size of the null-terminated
string starting at the specified offset in the tvbuff (throwing
an exception if the null terminator isn't found), allocates a
buffer big enough to hold that string, copies the string to that
buffer, and returns a pointer to that buffer and stores the
length of the string (including the terminating null) in the
variable pointed to by the "gint" pointer.
Replace many pieces of code allocating a buffer and copying a string
with calls to "tvb_get_string()" (for one thing, "tvb_get_string()"
doesn't require you to remember that the argument to
"tvb_get_nstringz0()" is the size of the buffer into which you're
copying the string, which might be the length of the string to be copied
*plus 1*).
Don't use fixed-length buffers for null-terminated strings (even if the
code that generates those packets has a #define to limit the length of
the string). Use "tvb_get_stringz()", instead.
In some cases where a value is fetched but is only used to pass an
argument to a "proto_tree_add_XXX" routine, use "proto_tree_add_item()"
instead.
svn path=/trunk/; revision=7859
2003-06-12 08:33:32 +00:00
|
|
|
guint32 baud = tvb_get_ntohl(tvb, offset+1);
|
2003-04-22 19:57:33 +00:00
|
|
|
if (baud == 0) {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 5, "%s Requests Baud Rate",source);
|
|
|
|
} else {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 5, "%s Baud Rate: %d",source,baud);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Baud Rate Packet>",source);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_SETDATASIZE:
|
|
|
|
len--;
|
|
|
|
if (len >= 1) {
|
Add new routines:
tvb_get_string() - takes a tvbuff, an offset, and a length as
arguments, allocates a buffer big enough to hold a string with
the specified number of bytes plus an added null terminator
(i.e., length+1), copies the specified number of bytes from the
tvbuff, at the specified offset, to that buffer and puts in a
null terminator, and returns a pointer to that buffer (or throws
an exception before allocating the buffer if that many bytes
aren't available in the tvbuff);
tvb_get_stringz() - takes a tvbuff, an offset, and a pointer to
a "gint" as arguments, gets the size of the null-terminated
string starting at the specified offset in the tvbuff (throwing
an exception if the null terminator isn't found), allocates a
buffer big enough to hold that string, copies the string to that
buffer, and returns a pointer to that buffer and stores the
length of the string (including the terminating null) in the
variable pointed to by the "gint" pointer.
Replace many pieces of code allocating a buffer and copying a string
with calls to "tvb_get_string()" (for one thing, "tvb_get_string()"
doesn't require you to remember that the argument to
"tvb_get_nstringz0()" is the size of the buffer into which you're
copying the string, which might be the length of the string to be copied
*plus 1*).
Don't use fixed-length buffers for null-terminated strings (even if the
code that generates those packets has a #define to limit the length of
the string). Use "tvb_get_stringz()", instead.
In some cases where a value is fetched but is only used to pass an
argument to a "proto_tree_add_XXX" routine, use "proto_tree_add_item()"
instead.
svn path=/trunk/; revision=7859
2003-06-12 08:33:32 +00:00
|
|
|
guint8 datasize = tvb_get_guint8(tvb, offset+1);
|
2003-04-22 19:57:33 +00:00
|
|
|
const char *ds = (datasize > 8) ? "<invalid>" : datasizes[datasize];
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, "%s Data Size: %s",source,ds);
|
|
|
|
} else {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Data Size Packet>",source);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_SETPARITY:
|
|
|
|
len--;
|
|
|
|
if (len >= 1) {
|
Add new routines:
tvb_get_string() - takes a tvbuff, an offset, and a length as
arguments, allocates a buffer big enough to hold a string with
the specified number of bytes plus an added null terminator
(i.e., length+1), copies the specified number of bytes from the
tvbuff, at the specified offset, to that buffer and puts in a
null terminator, and returns a pointer to that buffer (or throws
an exception before allocating the buffer if that many bytes
aren't available in the tvbuff);
tvb_get_stringz() - takes a tvbuff, an offset, and a pointer to
a "gint" as arguments, gets the size of the null-terminated
string starting at the specified offset in the tvbuff (throwing
an exception if the null terminator isn't found), allocates a
buffer big enough to hold that string, copies the string to that
buffer, and returns a pointer to that buffer and stores the
length of the string (including the terminating null) in the
variable pointed to by the "gint" pointer.
Replace many pieces of code allocating a buffer and copying a string
with calls to "tvb_get_string()" (for one thing, "tvb_get_string()"
doesn't require you to remember that the argument to
"tvb_get_nstringz0()" is the size of the buffer into which you're
copying the string, which might be the length of the string to be copied
*plus 1*).
Don't use fixed-length buffers for null-terminated strings (even if the
code that generates those packets has a #define to limit the length of
the string). Use "tvb_get_stringz()", instead.
In some cases where a value is fetched but is only used to pass an
argument to a "proto_tree_add_XXX" routine, use "proto_tree_add_item()"
instead.
svn path=/trunk/; revision=7859
2003-06-12 08:33:32 +00:00
|
|
|
guint8 parity = tvb_get_guint8(tvb, offset+1);
|
2003-04-22 19:57:33 +00:00
|
|
|
const char *pr = (parity > 5) ? "<invalid>" : parities[parity];
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, "%s Parity: %s",source,pr);
|
|
|
|
} else {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Parity Packet>",source);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_SETSTOPSIZE:
|
|
|
|
len--;
|
|
|
|
if (len >= 1) {
|
Add new routines:
tvb_get_string() - takes a tvbuff, an offset, and a length as
arguments, allocates a buffer big enough to hold a string with
the specified number of bytes plus an added null terminator
(i.e., length+1), copies the specified number of bytes from the
tvbuff, at the specified offset, to that buffer and puts in a
null terminator, and returns a pointer to that buffer (or throws
an exception before allocating the buffer if that many bytes
aren't available in the tvbuff);
tvb_get_stringz() - takes a tvbuff, an offset, and a pointer to
a "gint" as arguments, gets the size of the null-terminated
string starting at the specified offset in the tvbuff (throwing
an exception if the null terminator isn't found), allocates a
buffer big enough to hold that string, copies the string to that
buffer, and returns a pointer to that buffer and stores the
length of the string (including the terminating null) in the
variable pointed to by the "gint" pointer.
Replace many pieces of code allocating a buffer and copying a string
with calls to "tvb_get_string()" (for one thing, "tvb_get_string()"
doesn't require you to remember that the argument to
"tvb_get_nstringz0()" is the size of the buffer into which you're
copying the string, which might be the length of the string to be copied
*plus 1*).
Don't use fixed-length buffers for null-terminated strings (even if the
code that generates those packets has a #define to limit the length of
the string). Use "tvb_get_stringz()", instead.
In some cases where a value is fetched but is only used to pass an
argument to a "proto_tree_add_XXX" routine, use "proto_tree_add_item()"
instead.
svn path=/trunk/; revision=7859
2003-06-12 08:33:32 +00:00
|
|
|
guint8 stop = tvb_get_guint8(tvb, offset+1);
|
2003-04-22 19:57:33 +00:00
|
|
|
const char *st = (stop > 3) ? "<invalid>" : stops[stop];
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, "%s Stop: %s",source,st);
|
|
|
|
} else {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Stop Packet>",source);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_SETCONTROL:
|
|
|
|
len--;
|
|
|
|
if (len >= 1) {
|
Add new routines:
tvb_get_string() - takes a tvbuff, an offset, and a length as
arguments, allocates a buffer big enough to hold a string with
the specified number of bytes plus an added null terminator
(i.e., length+1), copies the specified number of bytes from the
tvbuff, at the specified offset, to that buffer and puts in a
null terminator, and returns a pointer to that buffer (or throws
an exception before allocating the buffer if that many bytes
aren't available in the tvbuff);
tvb_get_stringz() - takes a tvbuff, an offset, and a pointer to
a "gint" as arguments, gets the size of the null-terminated
string starting at the specified offset in the tvbuff (throwing
an exception if the null terminator isn't found), allocates a
buffer big enough to hold that string, copies the string to that
buffer, and returns a pointer to that buffer and stores the
length of the string (including the terminating null) in the
variable pointed to by the "gint" pointer.
Replace many pieces of code allocating a buffer and copying a string
with calls to "tvb_get_string()" (for one thing, "tvb_get_string()"
doesn't require you to remember that the argument to
"tvb_get_nstringz0()" is the size of the buffer into which you're
copying the string, which might be the length of the string to be copied
*plus 1*).
Don't use fixed-length buffers for null-terminated strings (even if the
code that generates those packets has a #define to limit the length of
the string). Use "tvb_get_stringz()", instead.
In some cases where a value is fetched but is only used to pass an
argument to a "proto_tree_add_XXX" routine, use "proto_tree_add_item()"
instead.
svn path=/trunk/; revision=7859
2003-06-12 08:33:32 +00:00
|
|
|
guint8 crt = tvb_get_guint8(tvb, offset+1);
|
2003-04-22 19:57:33 +00:00
|
|
|
const char *c = (crt > 19) ? "Control: <invalid>" : control[crt];
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, "%s %s",source,c);
|
|
|
|
} else {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Control Packet>",source);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_SETLINESTATEMASK:
|
|
|
|
case TNCOMPORT_NOTIFYLINESTATE:
|
|
|
|
len--;
|
|
|
|
if (len >= 1) {
|
|
|
|
const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
|
|
|
|
"%s Set Linestate Mask: %s" : "%s Linestate: %s";
|
|
|
|
char ls_buffer[512];
|
Add new routines:
tvb_get_string() - takes a tvbuff, an offset, and a length as
arguments, allocates a buffer big enough to hold a string with
the specified number of bytes plus an added null terminator
(i.e., length+1), copies the specified number of bytes from the
tvbuff, at the specified offset, to that buffer and puts in a
null terminator, and returns a pointer to that buffer (or throws
an exception before allocating the buffer if that many bytes
aren't available in the tvbuff);
tvb_get_stringz() - takes a tvbuff, an offset, and a pointer to
a "gint" as arguments, gets the size of the null-terminated
string starting at the specified offset in the tvbuff (throwing
an exception if the null terminator isn't found), allocates a
buffer big enough to hold that string, copies the string to that
buffer, and returns a pointer to that buffer and stores the
length of the string (including the terminating null) in the
variable pointed to by the "gint" pointer.
Replace many pieces of code allocating a buffer and copying a string
with calls to "tvb_get_string()" (for one thing, "tvb_get_string()"
doesn't require you to remember that the argument to
"tvb_get_nstringz0()" is the size of the buffer into which you're
copying the string, which might be the length of the string to be copied
*plus 1*).
Don't use fixed-length buffers for null-terminated strings (even if the
code that generates those packets has a #define to limit the length of
the string). Use "tvb_get_stringz()", instead.
In some cases where a value is fetched but is only used to pass an
argument to a "proto_tree_add_XXX" routine, use "proto_tree_add_item()"
instead.
svn path=/trunk/; revision=7859
2003-06-12 08:33:32 +00:00
|
|
|
guint8 ls = tvb_get_guint8(tvb, offset+1);
|
2003-04-22 19:57:33 +00:00
|
|
|
int print_count = 0;
|
|
|
|
int idx;
|
|
|
|
ls_buffer[0] = '\0';
|
|
|
|
for (idx = 0; idx < 8; idx++) {
|
|
|
|
int bit = ls & 1;
|
|
|
|
if (bit) {
|
|
|
|
if (print_count != 0) {
|
|
|
|
strcat(ls_buffer,", ");
|
|
|
|
}
|
|
|
|
strcat(ls_buffer,linestate_bits[idx]);
|
|
|
|
print_count++;
|
|
|
|
}
|
|
|
|
ls = ls >> 1;
|
|
|
|
}
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, print_pattern, source, ls_buffer);
|
|
|
|
} else {
|
|
|
|
const char *print_pattern = (cmd == TNCOMPORT_SETLINESTATEMASK) ?
|
|
|
|
"%s <Invalid Linestate Mask>" : "%s <Invalid Linestate Packet>";
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1 + len, print_pattern, source);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_SETMODEMSTATEMASK:
|
|
|
|
case TNCOMPORT_NOTIFYMODEMSTATE:
|
|
|
|
len--;
|
|
|
|
if (len >= 1) {
|
|
|
|
const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
|
|
|
|
"%s Set Modemstate Mask: %s" : "%s Modemstate: %s";
|
|
|
|
char ms_buffer[256];
|
|
|
|
guint8 ms = tvb_get_guint8(tvb, offset+1);
|
|
|
|
int print_count = 0;
|
|
|
|
int idx;
|
|
|
|
ms_buffer[0] = '\0';
|
|
|
|
for (idx = 0; idx < 8; idx++) {
|
|
|
|
int bit = ms & 1;
|
|
|
|
if (bit) {
|
|
|
|
if (print_count != 0) {
|
|
|
|
strcat(ms_buffer,", ");
|
|
|
|
}
|
|
|
|
strcat(ms_buffer,modemstate_bits[idx]);
|
|
|
|
print_count++;
|
|
|
|
}
|
|
|
|
ms = ms >> 1;
|
|
|
|
}
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, print_pattern, source, ms_buffer);
|
|
|
|
} else {
|
|
|
|
const char *print_pattern = (cmd == TNCOMPORT_SETMODEMSTATEMASK) ?
|
|
|
|
"%s <Invalid Modemstate Mask>" : "%s <Invalid Modemstate Packet>";
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1 + len, print_pattern, source);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_FLOWCONTROLSUSPEND:
|
|
|
|
len--;
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "%s Flow Control Suspend",source);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_FLOWCONTROLRESUME:
|
|
|
|
len--;
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "%s Flow Control Resume",source);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TNCOMPORT_PURGEDATA:
|
|
|
|
len--;
|
|
|
|
if (len >= 1) {
|
|
|
|
guint8 purge = tvb_get_guint8(tvb, offset+1);
|
|
|
|
const char *p = (purge > 3) ? "<Purge invalid>" : purges[purge];
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, "%s %s",source,p);
|
|
|
|
} else {
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1 + len, "%s <Invalid Purge Packet>",source);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 1, "Invalid %s subcommand %u",
|
|
|
|
optname, cmd);
|
|
|
|
offset++;
|
|
|
|
len--;
|
|
|
|
if (len > 0)
|
|
|
|
proto_tree_add_text(tree, tvb, offset, len, "Subcommand data");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-02-24 01:04:30 +00:00
|
|
|
static const value_string rfc_opt_vals[] = {
|
|
|
|
{ 0, "OFF" },
|
|
|
|
{ 1, "ON" },
|
|
|
|
{ 2, "RESTART-ANY" },
|
|
|
|
{ 3, "RESTART-XON" },
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
dissect_rfc_subopt(const char *optname _U_, tvbuff_t *tvb, int offset,
|
|
|
|
int len _U_, proto_tree *tree)
|
|
|
|
{
|
|
|
|
guint8 cmd;
|
|
|
|
|
|
|
|
cmd = tvb_get_guint8(tvb, offset);
|
|
|
|
proto_tree_add_text(tree, tvb, offset, 2, "%s",
|
|
|
|
val_to_str(cmd, rfc_opt_vals, "Unknown (%u)"));
|
|
|
|
}
|
|
|
|
|
|
|
|
static tn_opt options[] = {
|
|
|
|
{
|
|
|
|
"Binary Transmission", /* RFC 856 */
|
|
|
|
NULL, /* no suboption negotiation */
|
|
|
|
NO_LENGTH,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Echo", /* RFC 857 */
|
|
|
|
NULL, /* no suboption negotiation */
|
|
|
|
NO_LENGTH,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Reconnection", /* DOD Protocol Handbook */
|
|
|
|
NULL,
|
|
|
|
NO_LENGTH,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Suppress Go Ahead", /* RFC 858 */
|
|
|
|
NULL, /* no suboption negotiation */
|
|
|
|
NO_LENGTH,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Approx Message Size Negotiation", /* Ethernet spec(!) */
|
|
|
|
NULL,
|
|
|
|
NO_LENGTH,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Status", /* RFC 859 */
|
|
|
|
&ett_status_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Timing Mark", /* RFC 860 */
|
|
|
|
NULL, /* no suboption negotiation */
|
|
|
|
NO_LENGTH,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Remote Controlled Trans and Echo", /* RFC 726 */
|
|
|
|
&ett_rcte_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Line Width", /* DOD Protocol Handbook */
|
|
|
|
&ett_olw_subopt,
|
|
|
|
VARIABLE_LENGTH, /* XXX - fill me in */
|
|
|
|
0, /* XXX - fill me in */
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Page Size", /* DOD Protocol Handbook */
|
|
|
|
&ett_ops_subopt,
|
|
|
|
VARIABLE_LENGTH, /* XXX - fill me in */
|
|
|
|
0, /* XXX - fill me in */
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Carriage-Return Disposition", /* RFC 652 */
|
|
|
|
&ett_crdisp_subopt,
|
|
|
|
FIXED_LENGTH,
|
|
|
|
2,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Horizontal Tab Stops", /* RFC 653 */
|
|
|
|
&ett_htstops_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
|
|
|
dissect_htstops_subopt
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Horizontal Tab Disposition", /* RFC 654 */
|
|
|
|
&ett_htdisp_subopt,
|
|
|
|
FIXED_LENGTH,
|
|
|
|
2,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Formfeed Disposition", /* RFC 655 */
|
|
|
|
&ett_ffdisp_subopt,
|
|
|
|
FIXED_LENGTH,
|
|
|
|
2,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Vertical Tabstops", /* RFC 656 */
|
|
|
|
&ett_vtstops_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Vertical Tab Disposition", /* RFC 657 */
|
|
|
|
&ett_vtdisp_subopt,
|
|
|
|
FIXED_LENGTH,
|
|
|
|
2,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Linefeed Disposition", /* RFC 658 */
|
|
|
|
&ett_lfdisp_subopt,
|
|
|
|
FIXED_LENGTH,
|
|
|
|
2,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Extended ASCII", /* RFC 698 */
|
|
|
|
&ett_extasc_subopt,
|
|
|
|
FIXED_LENGTH,
|
|
|
|
2,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Logout", /* RFC 727 */
|
|
|
|
NULL, /* no suboption negotiation */
|
|
|
|
NO_LENGTH,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Byte Macro", /* RFC 735 */
|
|
|
|
&ett_bytemacro_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
2,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Data Entry Terminal", /* RFC 732, RFC 1043 */
|
|
|
|
&ett_det_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
2,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"SUPDUP", /* RFC 734, RFC 736 */
|
|
|
|
NULL, /* no suboption negotiation */
|
|
|
|
NO_LENGTH,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"SUPDUP Output", /* RFC 749 */
|
|
|
|
&ett_supdupout_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Send Location", /* RFC 779 */
|
|
|
|
&ett_sendloc_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
0,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Terminal Type", /* RFC 1091 */
|
|
|
|
&ett_termtype_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
|
|
|
dissect_string_subopt
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"End of Record", /* RFC 885 */
|
|
|
|
NULL, /* no suboption negotiation */
|
|
|
|
NO_LENGTH,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"TACACS User Identification", /* RFC 927 */
|
|
|
|
&ett_tacacsui_subopt,
|
|
|
|
FIXED_LENGTH,
|
|
|
|
4,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Output Marking", /* RFC 933 */
|
|
|
|
&ett_outmark_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
|
|
|
dissect_outmark_subopt,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Terminal Location Number", /* RFC 946 */
|
|
|
|
&ett_tlocnum_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Telnet 3270 Regime", /* RFC 1041 */
|
|
|
|
&ett_tn3270reg_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"X.3 PAD", /* RFC 1053 */
|
|
|
|
&ett_x3pad_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Negotiate About Window Size", /* RFC 1073, DW183 */
|
|
|
|
&ett_naws_subopt,
|
|
|
|
FIXED_LENGTH,
|
|
|
|
4,
|
|
|
|
dissect_naws_subopt
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Terminal Speed", /* RFC 1079 */
|
|
|
|
&ett_tspeed_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Remote Flow Control", /* RFC 1372 */
|
|
|
|
&ett_rfc_subopt,
|
|
|
|
FIXED_LENGTH,
|
|
|
|
1,
|
|
|
|
dissect_rfc_subopt
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Linemode", /* RFC 1184 */
|
|
|
|
&ett_linemode_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"X Display Location", /* RFC 1096 */
|
|
|
|
&ett_xdpyloc_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
|
|
|
dissect_string_subopt
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Environment Option", /* RFC 1408, RFC 1571 */
|
|
|
|
&ett_env_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Authentication Option", /* RFC 2941 */
|
|
|
|
&ett_auth_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Encryption Option", /* RFC 2946 */
|
|
|
|
&ett_enc_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"New Environment Option", /* RFC 1572 */
|
|
|
|
&ett_newenv_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"TN3270E", /* RFC 1647 */
|
|
|
|
&ett_tn3270e_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
2003-02-24 19:25:00 +00:00
|
|
|
NULL /* XXX - fill me in */
|
2003-02-24 01:04:30 +00:00
|
|
|
},
|
2003-04-22 19:57:33 +00:00
|
|
|
{
|
|
|
|
"XAUTH", /* XAUTH */
|
|
|
|
&ett_xauth_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
|
|
|
NULL /* XXX - fill me in */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"CHARSET", /* CHARSET */
|
|
|
|
&ett_charset_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
|
|
|
NULL /* XXX - fill me in */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"Remote Serial Port", /* Remote Serial Port */
|
|
|
|
&ett_rsp_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
|
|
|
NULL /* XXX - fill me in */
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"COM Port Control", /* RFC 2217 */
|
|
|
|
&ett_comport_subopt,
|
|
|
|
VARIABLE_LENGTH,
|
|
|
|
1,
|
|
|
|
dissect_comport_subopt
|
|
|
|
},
|
|
|
|
|
1999-04-05 21:54:41 +00:00
|
|
|
};
|
|
|
|
|
2000-03-23 10:25:38 +00:00
|
|
|
#define NOPTIONS (sizeof options / sizeof options[0])
|
|
|
|
|
|
|
|
static int
|
2000-11-09 10:56:33 +00:00
|
|
|
telnet_sub_option(proto_tree *telnet_tree, tvbuff_t *tvb, int start_offset)
|
1999-04-05 21:54:41 +00:00
|
|
|
{
|
|
|
|
proto_tree *ti, *option_tree;
|
2000-03-23 10:25:38 +00:00
|
|
|
int offset = start_offset;
|
2000-11-09 10:56:33 +00:00
|
|
|
guint8 opt_byte;
|
2003-02-24 01:04:30 +00:00
|
|
|
int subneg_len;
|
|
|
|
const char *opt;
|
|
|
|
gint ett;
|
2002-10-25 21:09:36 +00:00
|
|
|
int iac_offset;
|
2000-11-09 10:56:33 +00:00
|
|
|
guint len;
|
2003-02-24 01:04:30 +00:00
|
|
|
void (*dissect)(const char *, tvbuff_t *, int, int, proto_tree *);
|
2003-04-22 20:35:49 +00:00
|
|
|
gint cur_offset;
|
|
|
|
gboolean iac_found;
|
1999-04-05 21:54:41 +00:00
|
|
|
|
2000-03-23 10:25:38 +00:00
|
|
|
offset += 2; /* skip IAC and SB */
|
1999-04-05 21:54:41 +00:00
|
|
|
|
2003-02-24 01:04:30 +00:00
|
|
|
/* Get the option code */
|
2000-11-09 10:56:33 +00:00
|
|
|
opt_byte = tvb_get_guint8(tvb, offset);
|
2003-02-24 01:04:30 +00:00
|
|
|
if (opt_byte > NOPTIONS) {
|
2000-03-23 10:25:38 +00:00
|
|
|
opt = "<unknown option>";
|
2003-02-24 01:04:30 +00:00
|
|
|
ett = ett_telnet_subopt;
|
|
|
|
dissect = NULL;
|
|
|
|
} else {
|
|
|
|
opt = options[opt_byte].name;
|
|
|
|
if (options[opt_byte].subtree_index != NULL)
|
|
|
|
ett = *(options[opt_byte].subtree_index);
|
|
|
|
else
|
|
|
|
ett = ett_telnet_subopt;
|
|
|
|
dissect = options[opt_byte].dissect;
|
|
|
|
}
|
2000-03-23 10:25:38 +00:00
|
|
|
offset++;
|
|
|
|
|
2003-04-22 20:35:49 +00:00
|
|
|
/* Search for an unescaped IAC. */
|
2003-04-22 19:57:33 +00:00
|
|
|
cur_offset = offset;
|
2003-04-22 20:35:49 +00:00
|
|
|
iac_found = FALSE;
|
2000-11-09 10:56:33 +00:00
|
|
|
len = tvb_length_remaining(tvb, offset);
|
2003-04-22 19:57:33 +00:00
|
|
|
do {
|
|
|
|
iac_offset = tvb_find_guint8(tvb, cur_offset, len, TN_IAC);
|
2003-04-22 20:35:49 +00:00
|
|
|
iac_found = TRUE;
|
2003-04-22 19:57:33 +00:00
|
|
|
if (iac_offset == -1) {
|
|
|
|
/* None found - run to the end of the packet. */
|
|
|
|
offset += len;
|
|
|
|
} else {
|
2003-04-22 20:35:49 +00:00
|
|
|
if (((guint)(iac_offset + 1) >= len) ||
|
|
|
|
(tvb_get_guint8(tvb, iac_offset + 1) != TN_IAC)) {
|
|
|
|
/* We really found a single IAC, so we're done */
|
2003-04-22 19:57:33 +00:00
|
|
|
offset = iac_offset;
|
|
|
|
} else {
|
2003-04-22 20:35:49 +00:00
|
|
|
/*
|
|
|
|
* We saw an escaped IAC, so we have to move ahead to the
|
|
|
|
* next section
|
|
|
|
*/
|
|
|
|
iac_found = FALSE;
|
2003-04-22 19:57:33 +00:00
|
|
|
cur_offset = iac_offset + 2;
|
|
|
|
}
|
|
|
|
}
|
1999-04-05 21:54:41 +00:00
|
|
|
|
2003-04-22 19:57:33 +00:00
|
|
|
} while (!iac_found);
|
|
|
|
|
2000-03-23 10:25:38 +00:00
|
|
|
subneg_len = offset - start_offset;
|
1999-04-05 21:54:41 +00:00
|
|
|
|
2003-02-24 01:04:30 +00:00
|
|
|
ti = proto_tree_add_text(telnet_tree, tvb, start_offset, subneg_len,
|
|
|
|
"Suboption Begin: %s", opt);
|
|
|
|
option_tree = proto_item_add_subtree(ti, ett);
|
|
|
|
start_offset += 3; /* skip IAC, SB, and option code */
|
|
|
|
subneg_len -= 3;
|
1999-04-05 21:54:41 +00:00
|
|
|
|
2003-02-24 01:04:30 +00:00
|
|
|
if (subneg_len > 0) {
|
|
|
|
switch (options[opt_byte].len_type) {
|
|
|
|
|
|
|
|
case NO_LENGTH:
|
|
|
|
/* There isn't supposed to *be* sub-option negotiation for this. */
|
|
|
|
proto_tree_add_text(option_tree, tvb, start_offset, subneg_len,
|
|
|
|
"Bogus suboption data");
|
|
|
|
return offset;
|
|
|
|
|
|
|
|
case FIXED_LENGTH:
|
|
|
|
/* Make sure the length is what it's supposed to be. */
|
|
|
|
if (subneg_len != options[opt_byte].optlen) {
|
|
|
|
proto_tree_add_text(option_tree, tvb, start_offset, subneg_len,
|
|
|
|
"Suboption parameter length is %d, should be %d",
|
|
|
|
subneg_len, options[opt_byte].optlen);
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VARIABLE_LENGTH:
|
|
|
|
/* Make sure the length is greater than the minimum. */
|
|
|
|
if (subneg_len < options[opt_byte].optlen) {
|
|
|
|
proto_tree_add_text(option_tree, tvb, start_offset, subneg_len,
|
|
|
|
"Suboption parameter length is %d, should be at least %d",
|
|
|
|
subneg_len, options[opt_byte].optlen);
|
|
|
|
return offset;
|
2001-10-26 02:55:20 +00:00
|
|
|
}
|
2003-02-24 01:04:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now dissect the suboption parameters. */
|
2003-02-24 19:25:00 +00:00
|
|
|
if (dissect != NULL) {
|
|
|
|
/* We have a dissector for this suboption's parameters; call it. */
|
|
|
|
(*dissect)(opt, tvb, start_offset, subneg_len, option_tree);
|
|
|
|
} else {
|
|
|
|
/* We don't have a dissector for them; just show them as data. */
|
|
|
|
proto_tree_add_text(option_tree, tvb, start_offset, subneg_len,
|
|
|
|
"Option data");
|
|
|
|
}
|
1999-04-05 21:54:41 +00:00
|
|
|
}
|
2000-03-23 10:25:38 +00:00
|
|
|
return offset;
|
|
|
|
}
|
1999-04-05 21:54:41 +00:00
|
|
|
|
2000-03-23 10:25:38 +00:00
|
|
|
static int
|
2000-11-09 10:56:33 +00:00
|
|
|
telnet_will_wont_do_dont(proto_tree *telnet_tree, tvbuff_t *tvb,
|
2000-03-23 10:25:38 +00:00
|
|
|
int start_offset, char *type)
|
|
|
|
{
|
|
|
|
int offset = start_offset;
|
2000-11-09 10:56:33 +00:00
|
|
|
guint8 opt_byte;
|
2000-03-23 10:25:38 +00:00
|
|
|
const char *opt;
|
|
|
|
|
|
|
|
offset += 2; /* skip IAC and WILL,WONT,DO,DONT} */
|
2000-11-09 10:56:33 +00:00
|
|
|
opt_byte = tvb_get_guint8(tvb, offset);
|
|
|
|
if (opt_byte > NOPTIONS)
|
2000-03-23 10:25:38 +00:00
|
|
|
opt = "<unknown option>";
|
|
|
|
else
|
2003-02-24 01:04:30 +00:00
|
|
|
opt = options[opt_byte].name;
|
2000-03-23 10:25:38 +00:00
|
|
|
offset++;
|
2002-08-28 21:04:11 +00:00
|
|
|
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 3,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: %s %s", type, opt);
|
|
|
|
return offset;
|
1999-04-05 21:54:41 +00:00
|
|
|
}
|
|
|
|
|
2000-03-23 10:25:38 +00:00
|
|
|
static int
|
2000-11-09 10:56:33 +00:00
|
|
|
telnet_command(proto_tree *telnet_tree, tvbuff_t *tvb, int start_offset)
|
1999-04-05 21:54:41 +00:00
|
|
|
{
|
2000-03-23 10:25:38 +00:00
|
|
|
int offset = start_offset;
|
2002-08-02 23:36:07 +00:00
|
|
|
guchar optcode;
|
2002-08-28 21:04:11 +00:00
|
|
|
|
2000-03-23 10:25:38 +00:00
|
|
|
offset += 1; /* skip IAC */
|
2000-11-09 10:56:33 +00:00
|
|
|
optcode = tvb_get_guint8(tvb, offset);
|
2000-03-23 10:25:38 +00:00
|
|
|
offset++;
|
|
|
|
switch(optcode) {
|
1999-04-05 21:54:41 +00:00
|
|
|
|
|
|
|
case TN_EOF:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: End of File");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_SUSP:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Suspend Current Process");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_ABORT:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Abort Process");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_EOR:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: End of Record");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_SE:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Suboption End");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_NOP:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: No Operation");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_DM:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Data Mark");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_BRK:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Break");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_IP:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Interrupt Process");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_AO:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Abort Output");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_AYT:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Are You There?");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_EC:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Escape Character");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_EL:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Erase Line");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_GA:
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Command: Go Ahead");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_SB:
|
2000-11-09 10:56:33 +00:00
|
|
|
offset = telnet_sub_option(telnet_tree, tvb, start_offset);
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_WILL:
|
2000-11-09 10:56:33 +00:00
|
|
|
offset = telnet_will_wont_do_dont(telnet_tree, tvb, start_offset,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Will");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_WONT:
|
2000-11-09 10:56:33 +00:00
|
|
|
offset = telnet_will_wont_do_dont(telnet_tree, tvb, start_offset,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Won't");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_DO:
|
2000-11-09 10:56:33 +00:00
|
|
|
offset = telnet_will_wont_do_dont(telnet_tree, tvb, start_offset,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Do");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TN_DONT:
|
2000-11-09 10:56:33 +00:00
|
|
|
offset = telnet_will_wont_do_dont(telnet_tree, tvb, start_offset,
|
2000-03-23 10:25:38 +00:00
|
|
|
"Don't");
|
1999-04-05 21:54:41 +00:00
|
|
|
break;
|
2002-10-25 21:09:36 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
proto_tree_add_text(telnet_tree, tvb, start_offset, 2,
|
|
|
|
"Command: Unknown (0x%02x)", optcode);
|
|
|
|
break;
|
1999-04-05 21:54:41 +00:00
|
|
|
}
|
|
|
|
|
2000-03-23 10:25:38 +00:00
|
|
|
return offset;
|
1999-04-05 21:54:41 +00:00
|
|
|
}
|
|
|
|
|
2000-09-29 19:06:12 +00:00
|
|
|
static void
|
2000-11-09 10:56:33 +00:00
|
|
|
telnet_add_text(proto_tree *tree, tvbuff_t *tvb, int offset, int len)
|
2000-09-29 19:06:12 +00:00
|
|
|
{
|
2000-11-09 10:56:33 +00:00
|
|
|
gint next_offset;
|
2000-09-29 19:06:12 +00:00
|
|
|
int linelen;
|
2000-11-12 00:59:09 +00:00
|
|
|
guint8 c;
|
|
|
|
gboolean last_char_was_cr;
|
2000-09-29 19:06:12 +00:00
|
|
|
|
2000-11-13 08:58:17 +00:00
|
|
|
while (len != 0 && tvb_offset_exists(tvb, offset)) {
|
2000-09-29 19:06:12 +00:00
|
|
|
/*
|
|
|
|
* Find the end of the line.
|
|
|
|
*/
|
2002-07-17 06:55:29 +00:00
|
|
|
linelen = tvb_find_line_end(tvb, offset, len, &next_offset, FALSE);
|
2000-11-12 00:59:09 +00:00
|
|
|
len -= next_offset - offset; /* subtract out the line's characters */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In Telnet, CR NUL is the way you send a CR by itself in the
|
|
|
|
* default ASCII mode; don't treat CR by itself as a line ending,
|
|
|
|
* treat only CR NUL, CR LF, or LF by itself as a line ending.
|
|
|
|
*/
|
|
|
|
if (next_offset == offset + linelen + 1 && len >= 1) {
|
|
|
|
/*
|
|
|
|
* Well, we saw a one-character line ending, so either it's a CR
|
|
|
|
* or an LF; we have at least two characters left, including the
|
|
|
|
* CR.
|
|
|
|
*
|
|
|
|
* If the line ending is a CR, skip all subsequent CRs; at
|
|
|
|
* least one capture appeared to have multiple CRs at the end of
|
|
|
|
* a line.
|
|
|
|
*/
|
|
|
|
if (tvb_get_guint8(tvb, offset + linelen) == '\r') {
|
|
|
|
last_char_was_cr = TRUE;
|
2000-11-13 08:58:17 +00:00
|
|
|
while (len != 0 && tvb_offset_exists(tvb, next_offset)) {
|
2000-11-12 00:59:09 +00:00
|
|
|
c = tvb_get_guint8(tvb, next_offset);
|
|
|
|
next_offset++; /* skip over that character */
|
|
|
|
len--;
|
|
|
|
if (c == '\n' || (c == '\0' && last_char_was_cr)) {
|
|
|
|
/*
|
|
|
|
* LF is a line ending, whether preceded by CR or not.
|
|
|
|
* NUL is a line ending if preceded by CR.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
last_char_was_cr = (c == '\r');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now compute the length of the line *including* the end-of-line
|
|
|
|
* indication, if any; we display it all.
|
|
|
|
*/
|
2000-11-09 10:56:33 +00:00
|
|
|
linelen = next_offset - offset;
|
2000-09-29 19:06:12 +00:00
|
|
|
|
2000-11-09 10:56:33 +00:00
|
|
|
proto_tree_add_text(tree, tvb, offset, linelen,
|
|
|
|
"Data: %s",
|
|
|
|
tvb_format_text(tvb, offset, linelen));
|
2000-11-12 00:59:09 +00:00
|
|
|
offset = next_offset;
|
2000-09-29 19:06:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-04-08 07:07:42 +00:00
|
|
|
static void
|
2000-11-09 10:56:33 +00:00
|
|
|
dissect_telnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
1999-04-05 21:54:41 +00:00
|
|
|
{
|
|
|
|
proto_tree *telnet_tree, *ti;
|
|
|
|
|
2001-12-10 00:26:21 +00:00
|
|
|
if (check_col(pinfo->cinfo, COL_PROTOCOL))
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TELNET");
|
2000-11-09 10:56:33 +00:00
|
|
|
|
2001-12-10 00:26:21 +00:00
|
|
|
if (check_col(pinfo->cinfo, COL_INFO))
|
|
|
|
col_add_fstr(pinfo->cinfo, COL_INFO, "Telnet Data ...");
|
1999-04-05 21:54:41 +00:00
|
|
|
|
|
|
|
if (tree) {
|
2000-11-09 10:56:33 +00:00
|
|
|
gint offset = 0;
|
|
|
|
guint len;
|
2000-03-23 10:25:38 +00:00
|
|
|
int data_len;
|
2000-11-09 10:56:33 +00:00
|
|
|
gint iac_offset;
|
1999-04-05 21:54:41 +00:00
|
|
|
|
2002-01-24 09:20:54 +00:00
|
|
|
ti = proto_tree_add_item(tree, proto_telnet, tvb, offset, -1, FALSE);
|
1999-11-16 11:44:20 +00:00
|
|
|
telnet_tree = proto_item_add_subtree(ti, ett_telnet);
|
1999-04-05 21:54:41 +00:00
|
|
|
|
2000-03-23 10:25:38 +00:00
|
|
|
/*
|
|
|
|
* Scan through the buffer looking for an IAC byte.
|
|
|
|
*/
|
2000-11-13 08:58:17 +00:00
|
|
|
while ((len = tvb_length_remaining(tvb, offset)) > 0) {
|
2000-11-09 10:56:33 +00:00
|
|
|
iac_offset = tvb_find_guint8(tvb, offset, len, TN_IAC);
|
|
|
|
if (iac_offset != -1) {
|
2000-03-23 10:25:38 +00:00
|
|
|
/*
|
|
|
|
* We found an IAC byte.
|
|
|
|
* If there's any data before it, add that data to the
|
2000-09-29 19:06:12 +00:00
|
|
|
* tree, a line at a time.
|
2000-03-23 10:25:38 +00:00
|
|
|
*/
|
2000-11-09 10:56:33 +00:00
|
|
|
data_len = iac_offset - offset;
|
|
|
|
if (data_len > 0)
|
|
|
|
telnet_add_text(telnet_tree, tvb, offset, data_len);
|
2002-08-28 21:04:11 +00:00
|
|
|
|
2000-03-23 10:25:38 +00:00
|
|
|
/*
|
|
|
|
* Now interpret the command.
|
|
|
|
*/
|
2000-11-09 10:56:33 +00:00
|
|
|
offset = telnet_command(telnet_tree, tvb, iac_offset);
|
1999-04-05 21:54:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2000-11-09 10:56:33 +00:00
|
|
|
/*
|
|
|
|
* We found no IAC byte, so what remains in the buffer
|
|
|
|
* is the last of the data in the packet.
|
|
|
|
* Add it to the tree, a line at a time, and then quit.
|
|
|
|
*/
|
|
|
|
telnet_add_text(telnet_tree, tvb, offset, len);
|
|
|
|
break;
|
1999-04-05 21:54:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-29 05:47:07 +00:00
|
|
|
void
|
|
|
|
proto_register_telnet(void)
|
|
|
|
{
|
|
|
|
/* static hf_register_info hf[] = {
|
|
|
|
{ &variable,
|
|
|
|
{ "Name", "telnet.abbreviation", TYPE, VALS_POINTER }},
|
|
|
|
};*/
|
1999-11-16 11:44:20 +00:00
|
|
|
static gint *ett[] = {
|
|
|
|
&ett_telnet,
|
|
|
|
&ett_telnet_subopt,
|
2003-02-24 01:04:30 +00:00
|
|
|
&ett_status_subopt,
|
|
|
|
&ett_rcte_subopt,
|
|
|
|
&ett_olw_subopt,
|
|
|
|
&ett_ops_subopt,
|
|
|
|
&ett_crdisp_subopt,
|
|
|
|
&ett_htstops_subopt,
|
|
|
|
&ett_htdisp_subopt,
|
|
|
|
&ett_ffdisp_subopt,
|
|
|
|
&ett_vtstops_subopt,
|
|
|
|
&ett_vtdisp_subopt,
|
|
|
|
&ett_lfdisp_subopt,
|
|
|
|
&ett_extasc_subopt,
|
|
|
|
&ett_bytemacro_subopt,
|
|
|
|
&ett_det_subopt,
|
|
|
|
&ett_supdupout_subopt,
|
|
|
|
&ett_sendloc_subopt,
|
|
|
|
&ett_termtype_subopt,
|
|
|
|
&ett_tacacsui_subopt,
|
|
|
|
&ett_outmark_subopt,
|
|
|
|
&ett_tlocnum_subopt,
|
|
|
|
&ett_tn3270reg_subopt,
|
|
|
|
&ett_x3pad_subopt,
|
|
|
|
&ett_naws_subopt,
|
|
|
|
&ett_tspeed_subopt,
|
|
|
|
&ett_rfc_subopt,
|
|
|
|
&ett_linemode_subopt,
|
|
|
|
&ett_xdpyloc_subopt,
|
|
|
|
&ett_env_subopt,
|
|
|
|
&ett_auth_subopt,
|
|
|
|
&ett_enc_subopt,
|
|
|
|
&ett_newenv_subopt,
|
|
|
|
&ett_tn3270e_subopt,
|
2003-04-22 19:57:33 +00:00
|
|
|
&ett_xauth_subopt,
|
|
|
|
&ett_charset_subopt,
|
|
|
|
&ett_rsp_subopt,
|
|
|
|
&ett_comport_subopt,
|
1999-11-16 11:44:20 +00:00
|
|
|
};
|
1999-04-05 21:54:41 +00:00
|
|
|
|
2001-01-03 06:56:03 +00:00
|
|
|
proto_telnet = proto_register_protocol("Telnet", "TELNET", "telnet");
|
1999-07-29 05:47:07 +00:00
|
|
|
/* proto_register_field_array(proto_telnet, hf, array_length(hf));*/
|
1999-11-16 11:44:20 +00:00
|
|
|
proto_register_subtree_array(ett, array_length(ett));
|
1999-07-29 05:47:07 +00:00
|
|
|
}
|
2000-04-08 07:07:42 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
proto_reg_handoff_telnet(void)
|
|
|
|
{
|
2001-12-03 04:00:26 +00:00
|
|
|
dissector_handle_t telnet_handle;
|
|
|
|
|
|
|
|
telnet_handle = create_dissector_handle(dissect_telnet, proto_telnet);
|
|
|
|
dissector_add("tcp.port", TCP_PORT_TELNET, telnet_handle);
|
2000-04-08 07:07:42 +00:00
|
|
|
}
|