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