Note that non-GNU "make"s appear not to be able to build Ethereal, and
[metze/wireshark/wip.git] / packet-telnet.c
1 /* packet-pop.c
2  * Routines for telnet packet dissection
3  * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
4  *
5  * $Id: packet-telnet.c,v 1.2 1999/04/05 23:39:51 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@unicom.net>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-pop.c
12  * 
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.
17  * 
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.
22  * 
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.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
40 #endif
41
42 #include <string.h>
43 #include <glib.h>
44 #include "packet.h"
45 #include "etypes.h"
46
47 /* Some defines for Telnet */
48
49 #define TN_IAC   255
50 #define TN_DONT  254
51 #define TN_DO    253
52 #define TN_WONT  252
53 #define TN_WILL  251
54 #define TN_SB    250
55 #define TN_GA    249
56 #define TN_EL    248
57 #define TN_EC    247
58 #define TN_AYT   246
59 #define TN_AO    245
60 #define TN_IP    244
61 #define TN_BRK   243
62 #define TN_DM    242
63 #define TN_NOP   241
64 #define TN_SE    240
65 #define TN_EOR   239
66 #define TN_ABORT 238
67 #define TN_SUSP  237
68 #define TN_EOF   236
69
70 char *options[] = {
71   "Binary Transmission",
72   "Echo",
73   "Reconnection",
74   "Suppress Go Ahead",
75   "Approx Message Size Negotiation",
76   "Status",
77   "Timing Mark",
78   "Remote Controlled Trans and Echo",
79   "Output Line Width",
80   "Output Page Size",
81   "Output Carriage-Return Disposition",
82   "Output Horizontal Tab Stops",
83   "Output Horizontal Tab Disposition",
84   "Output Formfeed Disposition",
85   "Output Vertical Tabstops",
86   "Output Vertical Tab Disposition",
87   "Output Linefeed Disposition",
88   "Extended ASCII",
89   "Logout",
90   "Byte Macro",
91   "Data Entry Terminal",
92   "SUPDUP",
93   "SUPDUP Output",
94   "Send Location",
95   "Terminal Type",
96   "End of Record",
97   "TACACS User Identification",
98   "Output Marking",
99   "Terminal Location Number",
100   "Telnet 3270 Regime",
101   "X.3 PAD",
102   "Negotiate About Window Size",
103   "Terminal Speed",
104   "Remote Flow Control",
105   "Linemode",
106   "X Display Location",
107   "Environment Option",
108   "Authentication Option",
109   "Encryption Option",
110   "New Environment Option",
111   "TN3270E"
112 };
113
114 extern packet_info pi;
115
116 void telnet_sub_option(proto_tree *telnet_tree, char *rr, int *i, int offset, int max_data)
117 {
118   proto_tree *ti, *option_tree;
119   int subneg_len, req, si1, not_found = 1;
120   volatile int i1;
121   char *opt, sub_opt_data[1500];
122
123   memset(sub_opt_data, '\0', sizeof(sub_opt_data));
124
125   /* Figure out the option and type */
126
127   opt = options[(unsigned int)rr[*i]];
128   req = (unsigned int)rr[*i + 1];
129
130   i1 = *i + 2; si1 = i1;
131   while ((i1 < max_data) && (not_found)) {  
132
133     if ((unsigned char)rr[i1] == (unsigned char)TN_IAC)
134       not_found = 0;
135     else
136       i1++;
137
138   }
139
140   subneg_len = i1 - *i + 2;
141
142   ti = proto_tree_add_item(telnet_tree, offset, subneg_len, "Suboption Begin: %s", opt);
143
144   option_tree = proto_tree_new();
145
146   proto_item_add_subtree(ti, option_tree, ETT_TELNET_SUBOPT);
147
148   proto_tree_add_item(option_tree, offset + 2, subneg_len - 2, "%s %s", (req ? "Send your" : "Here's my"), opt);
149
150   if (req == 0) {  /* Add the value */
151
152     memcpy(sub_opt_data, rr + *i + 2, subneg_len - 2);
153     proto_tree_add_item(option_tree, offset + 4, subneg_len - 4, "Value: %s", format_text(sub_opt_data, subneg_len - 4));
154     *i += subneg_len - 2;
155
156   }
157   else {
158
159     *i += subneg_len - 2;
160
161   }
162 }
163
164 void telnet_command(proto_tree *telnet_tree, char *rr, int *i, int offset, int max_data) 
165 {
166   char *opt;
167   
168   switch((unsigned char)rr[*i]) {
169
170   case TN_EOF:
171
172     proto_tree_add_item(telnet_tree, offset, 2, "Command: End of File");
173     (*i)++;
174     break;
175
176   case TN_SUSP:
177
178     proto_tree_add_item(telnet_tree, offset, 2, "Command: Suspend Current Process");
179     (*i)++;
180     break;
181
182   case TN_ABORT:
183
184     proto_tree_add_item(telnet_tree, offset, 2, "Command: Abort Process");
185     (*i)++;
186     break;
187
188   case TN_EOR:
189
190     proto_tree_add_item(telnet_tree, offset, 2, "Command: End of Record");
191     (*i)++;
192     break;
193
194   case TN_SE:
195
196     proto_tree_add_item(telnet_tree, offset, 2, "Command: Suboption End");
197     (*i)++;
198     break;
199
200   case TN_NOP:
201
202     proto_tree_add_item(telnet_tree, offset, 2, "Command: No Operation");
203     (*i)++;
204     break;
205
206   case TN_DM:
207
208     proto_tree_add_item(telnet_tree, offset, 2, "Command: Data Mark");
209     (*i)++;
210     break;
211
212   case TN_BRK:
213
214     proto_tree_add_item(telnet_tree, offset, 2, "Command: Break");
215     (*i)++;
216     break;
217
218   case TN_IP:
219
220     proto_tree_add_item(telnet_tree, offset, 2, "Command: Interrupt Process");
221     (*i)++;
222     break;
223
224   case TN_AO:
225
226     proto_tree_add_item(telnet_tree, offset, 2, "Command: Abort Output");
227     (*i)++;
228     break;
229
230   case TN_AYT:
231
232     proto_tree_add_item(telnet_tree, offset, 2, "Command: Are You There?");
233     (*i)++;
234     break;
235
236   case TN_EC:
237
238     proto_tree_add_item(telnet_tree, offset, 2, "Command: Escape Character");
239     (*i)++;
240     break;
241
242   case TN_EL:
243
244     proto_tree_add_item(telnet_tree, offset, 2, "Command: Erase Line");
245     (*i)++;
246     break;
247
248   case TN_GA:
249
250     proto_tree_add_item(telnet_tree, offset, 2, "Command: Go Ahead");
251     (*i)++;
252     break;
253
254   case TN_SB:
255
256     (*i)++;
257     telnet_sub_option(telnet_tree, rr, i, offset, max_data);
258     break;
259
260   case TN_WILL:
261
262     if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
263       opt = "<unknown option>";
264     else
265       opt = options[(unsigned int)rr[*i + 1]];
266                       
267     proto_tree_add_item(telnet_tree, offset, 3, "Command: Will %s", opt);
268     *i += 2; /* skip two chars */
269     break;
270
271   case TN_WONT:
272
273     if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
274       opt = "<unknown option>";
275     else
276       opt = options[(unsigned int)rr[*i + 1]];
277                       
278     proto_tree_add_item(telnet_tree, offset, 3, "Command: Won't %s", opt);
279     *i += 2; /* skip two chars */
280     break;
281
282   case TN_DO:
283
284     if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
285       opt = "<unknown option>";
286     else
287       opt = options[(unsigned int)rr[*i + 1]];
288                       
289     proto_tree_add_item(telnet_tree, offset, 3, "Command: Do %s", opt);
290     *i += 2; /* skip two chars */
291     break;
292
293   case TN_DONT:
294
295     if (rr[*i + 1] > (sizeof(options)/sizeof(char *)))
296       opt = "<unknown option>";
297     else
298       opt = options[(unsigned int)rr[*i + 1]];
299                       
300     proto_tree_add_item(telnet_tree, offset, 3, "Command: Don't %s", opt);
301     *i += 2; /* skip two chars */
302     break;
303
304   }
305
306 }
307
308 void
309 dissect_telnet(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int max_data)
310 {
311         proto_tree      *telnet_tree, *ti;
312         gchar           rr[1500];
313         int i1;
314         int i2;
315
316         memset(rr, '\0', sizeof(rr));
317
318         if (check_col(fd, COL_PROTOCOL))
319                 col_add_str(fd, COL_PROTOCOL, "TELNET");
320
321         if (check_col(fd, COL_INFO)) {
322
323           col_add_fstr(fd, COL_INFO, "Telnet Data ...");
324
325         }
326
327         if (tree) {
328
329           char data[1500];
330           int i3;
331
332           memset(data, '\0', sizeof(data));
333
334           memcpy(rr, pd + offset, max_data);
335
336           ti = proto_tree_add_item(tree, offset, END_OF_FRAME,
337                                 "Telnet Protocol");
338           telnet_tree = proto_tree_new();
339           proto_item_add_subtree(ti, telnet_tree, ETT_TELNET);
340
341           i1 = i2 = i3 = 0;
342
343           while (i1 < max_data) {
344
345             if ((unsigned char)rr[i1] == (unsigned char)TN_IAC) {
346
347               if (strlen(data) > 0) {
348
349                 proto_tree_add_item(telnet_tree, offset + i2, strlen(data), "Data: %s", format_text(data, strlen(data)));
350                 memset(data, '\0', sizeof(data));
351                 i3 = 0;
352
353               }
354               
355               i1++;
356               telnet_command(telnet_tree, rr, &i1, offset + i1 - 1, max_data);
357               i2 = i1;
358
359             }
360             else {
361
362               data[i3] = rr[i1];
363               i3++;
364               i1++;
365
366
367             }
368           }
369
370           if (strlen(data) > 0) { /* Still some data to add */
371
372             proto_tree_add_item(telnet_tree, offset + i2, strlen(data), "Data: %s", format_text(data, strlen(data)));
373
374           }
375
376         }
377
378 }
379
380
381
382
383
384