Ethereal-dev: [ethereal-dev] Here is a telnet decoder

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Richard Sharpe <sharpe@xxxxxxxxxx>
Date: Sun, 04 Apr 1999 11:45:17 +0900
Hi,

here is a Telnet decoder. I have used RFC1700 for the values of various
things.

It does a reasonably complete job, and I would appreciate feedback.

I have included strings.h surrounded by #ifdef HAVE_STRINGS_H

There is more work to do on options, and I am not happy about the display
in the info line, but I have to do the washing up now to keep the wife happy.

SMB will have to wait until next week.
--- packet.h.orig	Sun Apr  4 18:07:32 1999
+++ packet.h	Sun Apr  4 18:44:18 1999
@@ -204,6 +204,8 @@
 	ETT_TFTP,
 	ETT_POP,
 	ETT_FTP,
+	ETT_TELNET,
+	ETT_TELNET_SUBOPT,
 	NUM_TREE_TYPES	/* last item number plus one */
 };

@@ -330,6 +332,7 @@
 void dissect_pop(const u_char *, int, frame_data *, proto_tree *, int);
 void dissect_rip(const u_char *, int, frame_data *, proto_tree *);
 void dissect_tcp(const u_char *, int, frame_data *, proto_tree *);
+void dissect_telnet(const u_char *, int, frame_data *, proto_tree *, int);
 void dissect_tftp(const u_char *, int, frame_data *, proto_tree *);
 void dissect_trmac(const u_char *, int, frame_data *, proto_tree *);
 void dissect_udp(const u_char *, int, frame_data *, proto_tree *);
--- packet-tcp.c.orig	Sun Apr  4 16:48:13 1999
+++ packet-tcp.c	Sun Apr  4 17:52:30 1999
@@ -65,6 +65,7 @@

 #define TCP_PORT_FTPDATA  20
 #define TCP_PORT_FTP      21
+#define TCP_PORT_TELNET   23
 #define TCP_PORT_SMTP     25
 #define TCP_PORT_HTTP     80
 #define TCP_PORT_POP      110
@@ -454,9 +455,15 @@
      (it could be an ACK-only packet) */
   if (packet_max > offset) {
     switch(MIN(th.th_sport, th.th_dport)) {
-      case TCP_PORT_PRINTER:
-        dissect_lpd(pd, offset, fd, tree);
-        break;
+
+    case TCP_PORT_PRINTER:
+      dissect_lpd(pd, offset, fd, tree);
+      break;
+
+    case TCP_PORT_TELNET:
+      pi.match_port = TCP_PORT_TELNET;
+      dissect_telnet(pd, offset, fd, tree, payload);
+      break;

     case TCP_PORT_FTPDATA:
       pi.match_port = TCP_PORT_FTPDATA;
--- packet-telnet.c.orig	Sun Apr  4 20:50:25 1999
+++ packet-telnet.c	Sun Apr  4 20:55:51 1999
@@ -0,0 +1,388 @@
+/* packet-pop.c
+ * Routines for telnet packet dissection
+ * Copyright 1999, Richard Sharpe <rsharpe@xxxxxxxxxx>
+ *
+ *
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@xxxxxxxxxx>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from packet-pop.c
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include "packet.h"
+#include "etypes.h"
+
+/* Some defines for Telnet */
+
+#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
+
+char *options[] = {
+  "Binary Transmission",
+  "Echo",
+  "Reconnection",
+  "Suppress Go Ahead",
+  "Approx Message Size Negotiation",
+  "Status",
+  "Timing Mark",
+  "Remote Controlled Trans and Echo",
+  "Output Line Width",
+  "Output Page Size",
+  "Output Carriage-Return Disposition",
+  "Output Horizontal Tab Stops",
+  "Output Horizontal Tab Disposition",
+  "Output Formfeed Disposition",
+  "Output Vertical Tabstops",
+  "Output Vertical Tab Disposition",
+  "Output Linefeed Disposition",
+  "Extended ASCII",
+  "Logout",
+  "Byte Macro",
+  "Data Entry Terminal",
+  "SUPDUP",
+  "SUPDUP Output",
+  "Send Location",
+  "Terminal Type",
+  "End of Record",
+  "TACACS User Identification",
+  "Output Marking",
+  "Terminal Location Number",
+  "Telnet 3270 Regime",
+  "X.3 PAD",
+  "Negotiate About Window Size",
+  "Terminal Speed",
+  "Remote Flow Control",
+  "Linemode",
+  "X Display Location",
+  "Environment Option",
+  "Authentication Option",
+  "Encryption Option",
+  "New Environment Option",
+  "TN3270E"
+};
+
+extern packet_info pi;
+
+void telnet_sub_option(proto_tree *telnet_tree, char *rr, int *i, int offset, int max_data)
+{
+  proto_tree *ti, *option_tree;
+  int subneg_len, req, si1, not_found = 1;
+  volatile int i1;
+  char *opt, sub_opt_data[1500];
+
+  bzero(sub_opt_data, sizeof(sub_opt_data));
+
+  /* Figure out the option and type */
+
+  opt = options[(unsigned int)rr[*i]];
+  req = (unsigned int)rr[*i + 1];
+
+  i1 = *i + 2; si1 = i1;
+  while ((i1 < max_data) && (not_found)) {
+
+    if ((unsigned char)rr[i1] == (unsigned char)TN_IAC)
+      not_found = 0;
+    else
+      i1++;
+
+  }
+
+  subneg_len = i1 - *i + 2;
+
+  ti = proto_tree_add_item(telnet_tree, offset, subneg_len, "Suboption Begin: %s", opt);
+
+  option_tree = proto_tree_new();
+
+  proto_item_add_subtree(ti, option_tree, ETT_TELNET_SUBOPT);
+
+  proto_tree_add_item(option_tree, offset + 2, subneg_len - 2, "%s %s", (req ? "Send your" : "Here's my"), opt);
+
+  if (req == 0) {  /* Add the value */
+
+    bcopy(rr + *i + 2, sub_opt_data, subneg_len - 2);
+    proto_tree_add_item(option_tree, offset + 4, subneg_len - 4, "Value: %s", format_line(sub_opt_data, subneg_len - 4));
+    *i += subneg_len - 2;
+
+  }
+  else {
+
+    *i += subneg_len - 2;
+
+  }
+}
+
+void telnet_command(proto_tree *telnet_tree, char *rr, int *i, int offset, int max_data)
+{
+  char *opt;
+
+  switch((unsigned char)rr[*i]) {
+
+  case TN_EOF:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: End of File");
+    (*i)++;
+    break;
+
+  case TN_SUSP:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Suspend Current Process");
+    (*i)++;
+    break;
+
+  case TN_ABORT:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Abort Process");
+    (*i)++;
+    break;
+
+  case TN_EOR:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: End of Record");
+    (*i)++;
+    break;
+
+  case TN_SE:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Suboption End");
+    (*i)++;
+    break;
+
+  case TN_NOP:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: No Operation");
+    (*i)++;
+    break;
+
+  case TN_DM:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Data Mark");
+    (*i)++;
+    break;
+
+  case TN_BRK:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Break");
+    (*i)++;
+    break;
+
+  case TN_IP:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Interrupt Process");
+    (*i)++;
+    break;
+
+  case TN_AO:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Abort Output");
+    (*i)++;
+    break;
+
+  case TN_AYT:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Are You There?");
+    (*i)++;
+    break;
+
+  case TN_EC:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Escape Character");
+    (*i)++;
+    break;
+
+  case TN_EL:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Erase Line");
+    (*i)++;
+    break;
+
+  case TN_GA:
+
+    proto_tree_add_item(telnet_tree, offset, 2, "Command: Go Ahead");
+    (*i)++;
+    break;
+
+  case TN_SB:
+
+    (*i)++;
+    telnet_sub_option(telnet_tree, rr, i, offset, max_data);
+    break;
+
+  case TN_WILL:
+
+    if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
+      opt = "<unknown option>";
+    else
+      opt = options[(unsigned int)rr[*i + 1]];
+
+    proto_tree_add_item(telnet_tree, offset, 3, "Command: Will %s", opt);
+    *i += 2; /* skip two chars */
+    break;
+
+  case TN_WONT:
+
+    if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
+      opt = "<unknown option>";
+    else
+      opt = options[(unsigned int)rr[*i + 1]];
+
+    proto_tree_add_item(telnet_tree, offset, 3, "Command: Won't %s", opt);
+    *i += 2; /* skip two chars */
+    break;
+
+  case TN_DO:
+
+    if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
+      opt = "<unknown option>";
+    else
+      opt = options[(unsigned int)rr[*i + 1]];
+
+    proto_tree_add_item(telnet_tree, offset, 3, "Command: Do %s", opt);
+    *i += 2; /* skip two chars */
+    break;
+
+  case TN_DONT:
+
+    if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
+      opt = "<unknown option>";
+    else
+      opt = options[(unsigned int)rr[*i + 1]];
+
+    proto_tree_add_item(telnet_tree, offset, 3, "Command: Don't %s", opt);
+    *i += 2; /* skip two chars */
+    break;
+
+  }
+
+}
+
+void
+dissect_telnet(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
+{
+        proto_tree      *telnet_tree, *ti;
+	gchar           rr[1500];
+	int i1;
+	int i2;
+
+	bzero(rr, sizeof(rr));
+
+	if (check_col(fd, COL_PROTOCOL))
+		col_add_str(fd, COL_PROTOCOL, "TELNET");
+
+	if (check_col(fd, COL_INFO)) {
+
+	  col_add_fstr(fd, COL_INFO, "Telnet Data ...");
+
+	}
+
+	if (tree) {
+
+	  char data[1500];
+	  int i3;
+
+	  bzero(data, sizeof(data));
+
+	  bcopy(pd + offset, rr, max_data);
+
+	  ti = proto_tree_add_item(tree, offset, END_OF_FRAME,
+				"Telnet Protocol");
+	  telnet_tree = proto_tree_new();
+	  proto_item_add_subtree(ti, telnet_tree, ETT_TELNET);
+
+	  i1 = i2 = i3 = 0;
+
+	  while (i1 < max_data) {
+
+	    if ((unsigned char)rr[i1] == (unsigned char)TN_IAC) {
+
+	      if (strlen(data) > 0) {
+
+		proto_tree_add_item(telnet_tree, offset + i2, strlen(data), "Data: %s", format_line(data, strlen(data)));
+		bzero(data, sizeof(data));
+		i3 = 0;
+
+	      }
+
+	      i1++;
+	      telnet_command(telnet_tree, rr, &i1, offset + i1 - 1, max_data);
+	      i2 = i1;
+
+	    }
+	    else {
+
+	      data[i3] = rr[i1];
+	      i3++;
+	      i1++;
+
+
+	    }
+	  }
+
+	  if (strlen(data) > 0) { /* Still some data to add */
+
+	    proto_tree_add_item(telnet_tree, offset + i2, strlen(data), "Data: %s", format_line(data, strlen(data)));
+
+	  }
+
+	}
+
+}
+
+
+
+
+
+

Regards
-------
Richard Sharpe, sharpe@xxxxxxxxxx, NIC-Handle:RJS96
NS Computer Software and Services P/L, 
Ph: +61-8-8281-0063, FAX: +61-8-8250-2080, 
Samba (Team member), Linux, Apache, Digital UNIX, AIX, C, ...