When dissecting DNS or NBNS queries or replies, add the item to the tree
[obnox/wireshark/wip.git] / packet.c
1 /* packet.c
2  * Routines for packet disassembly
3  *
4  * $Id: packet.c,v 1.13 1998/12/04 05:59:13 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #include <gtk/gtk.h>
35
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <time.h>
41
42 #ifdef NEED_SNPRINTF_H
43 # include "snprintf.h"
44 #endif
45
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
48 #endif
49
50 #include "ethereal.h"
51 #include "packet.h"
52 #include "etypes.h"
53 #include "file.h"
54
55 extern GtkWidget    *byte_view;
56 extern GdkFont      *m_r_font, *m_b_font;
57 extern capture_file  cf;
58
59 gchar *
60 ether_to_str(guint8 *ad) {
61   static gchar  str[3][18];
62   static gchar *cur;
63
64   if (cur == &str[0][0]) {
65     cur = &str[1][0];
66   } else if (cur == &str[1][0]) {  
67     cur = &str[2][0];
68   } else {  
69     cur = &str[0][0];
70   }
71   sprintf(cur, "%02x:%02x:%02x:%02x:%02x:%02x", ad[0], ad[1], ad[2],
72     ad[3], ad[4], ad[5]);
73   return cur;
74 }
75
76 gchar *
77 ip_to_str(guint8 *ad) {
78   static gchar  str[3][16];
79   static gchar *cur;
80
81   if (cur == &str[0][0]) {
82     cur = &str[1][0];
83   } else if (cur == &str[1][0]) {  
84     cur = &str[2][0];
85   } else {  
86     cur = &str[0][0];
87   }
88   sprintf(cur, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]);
89   return cur;
90 }
91
92 void
93 packet_hex_print(GtkText *bv, guchar *pd, gint len, gint bstart, gint blen) {
94   gint     i = 0, j, k, cur;
95   gchar    line[128], hexchars[] = "0123456789abcdef";
96   GdkFont *cur_font, *new_font;
97   
98   while (i < len) {
99     /* Print the line number */
100     sprintf(line, "%04x  ", i);
101     gtk_text_insert(bv, m_r_font, NULL, NULL, line, -1);
102     /* Do we start in bold? */
103     cur_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font;
104     j   = i;
105     k   = i + BYTE_VIEW_WIDTH;
106     cur = 0;
107     /* Print the hex bit */
108     while (i < k) {
109       if (i < len) {
110         line[cur++] = hexchars[(pd[i] & 0xf0) >> 4];
111         line[cur++] = hexchars[pd[i] & 0x0f];
112       } else {
113         line[cur++] = ' '; line[cur++] = ' ';
114       }
115       line[cur++] = ' ';
116       i++;
117       /* Did we cross a bold/plain boundary? */
118       new_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font;
119       if (cur_font != new_font) {
120         gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
121         cur_font = new_font;
122         cur = 0;
123       }
124     }
125     line[cur++] = ' ';
126     gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
127     cur = 0;
128     i = j;
129     /* Print the ASCII bit */
130     cur_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font;
131     while (i < k) {
132       if (i < len) {
133         line[cur++] = (isgraph(pd[i])) ? pd[i] : '.';
134       } else {
135         line[cur++] = ' ';
136       }
137       i++;
138       /* Did we cross a bold/plain boundary? */
139       new_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font;
140       if (cur_font != new_font) {
141         gtk_text_insert(bv, cur_font, NULL, NULL, line, cur);
142         cur_font = new_font;
143         cur = 0;
144       }
145     }
146     line[cur++] = '\n';
147     line[cur]   = '\0';
148     gtk_text_insert(bv, cur_font, NULL, NULL, line, -1);
149   }
150 }
151
152 GtkWidget *
153 add_item_to_tree(GtkWidget *tree, gint start, gint len,
154   gchar *format, ...) {
155   GtkWidget *ti;
156   va_list    ap;
157   gchar      label_str[256];
158   
159   va_start(ap, format);
160   vsnprintf(label_str, 256, format, ap);
161   ti = gtk_tree_item_new_with_label(label_str);
162   gtk_object_set_data(GTK_OBJECT(ti), E_TREEINFO_START_KEY, (gpointer) start);
163   gtk_object_set_data(GTK_OBJECT(ti), E_TREEINFO_LEN_KEY, (gpointer) len);
164   gtk_tree_append(GTK_TREE(tree), ti);
165   gtk_widget_show(ti);
166
167   return ti;
168 }
169
170 void
171 set_item_len(GtkWidget *ti, gint len)
172 {
173   gtk_object_set_data(GTK_OBJECT(ti), E_TREEINFO_LEN_KEY, (gpointer) len);
174 }
175
176 void
177 add_subtree(GtkWidget *ti, GtkWidget *subtree, gint idx) {
178   static gint tree_type[NUM_TREE_TYPES];
179
180   gtk_tree_item_set_subtree(GTK_TREE_ITEM(ti), subtree);
181   if (tree_type[idx])
182     gtk_tree_item_expand(GTK_TREE_ITEM(ti));
183   gtk_signal_connect(GTK_OBJECT(ti), "expand", (GtkSignalFunc) expand_tree,
184     (gpointer) &tree_type[idx]);
185   gtk_signal_connect(GTK_OBJECT(ti), "collapse", (GtkSignalFunc) collapse_tree,
186     (gpointer) &tree_type[idx]);
187 }
188
189 void
190 expand_tree(GtkWidget *w, gpointer data) {
191   gint *val = (gint *) data;
192   *val = 1;
193 }
194
195 void
196 collapse_tree(GtkWidget *w, gpointer data) {
197   gint *val = (gint *) data;
198   *val = 0;
199 }
200
201 /* Tries to match val against each element in the value_string array vs.
202    Returns the associated string ptr on a match.
203    Formats val with fmt, and returns the resulting string, on failure. */
204 gchar*
205 val_to_str(guint32 val, const value_string *vs, const char *fmt) {
206   gchar *ret;
207   static gchar  str[3][64];
208   static gchar *cur;
209
210   ret = match_strval(val, vs);
211   if (ret != NULL)
212     return ret;
213   if (cur == &str[0][0]) {
214     cur = &str[1][0];
215   } else if (cur == &str[1][0]) {  
216     cur = &str[2][0];
217   } else {  
218     cur = &str[0][0];
219   }
220   snprintf(cur, 64, fmt, val);
221   return cur;
222 }
223
224 /* Tries to match val against each element in the value_string array vs.
225    Returns the associated string ptr on a match, or NULL on failure. */
226 gchar*
227 match_strval(guint32 val, const value_string *vs) {
228   gint i = 0;
229   
230   while (vs[i].strptr) {
231     if (vs[i].value == val)
232       return(vs[i].strptr);
233     i++;
234   }
235   
236   return(NULL);
237 }
238
239 /* Checks to see if a particular packet information element is needed for
240    the packet list */
241 gint
242 check_col(frame_data *fd, gint el) {
243   int i;
244   
245   if (fd->cinfo) {
246     for (i = 0; i < fd->cinfo->num_cols; i++) {
247       if (fd->cinfo->fmt_matx[i][el])
248         return TRUE;
249     }
250   }
251   return FALSE;
252 }
253
254 /* To do: Add check_col checks to the pinfo_add* routines */
255
256 /* Adds a vararg list to a packet info string. */
257 void
258 col_add_fstr(frame_data *fd, gint el, gchar *format, ...) {
259   va_list    ap;
260   int        i;
261   
262   va_start(ap, format);
263   for (i = 0; i < fd->cinfo->num_cols; i++) {
264     if (fd->cinfo->fmt_matx[i][el])
265       vsnprintf(fd->cinfo->col_data[i], COL_MAX_LEN, format, ap);
266   }
267 }
268
269 void
270 col_add_str(frame_data *fd, gint el, gchar* str) {
271   int i;
272   
273   for (i = 0; i < fd->cinfo->num_cols; i++) {
274     if (fd->cinfo->fmt_matx[i][el]) {
275       strncpy(fd->cinfo->col_data[i], str, COL_MAX_LEN);
276       fd->cinfo->col_data[i][COL_MAX_LEN - 1] = 0;
277     }
278   }
279 }
280
281 static const char *mon_names[12] = {
282         "Jan",
283         "Feb",
284         "Mar",
285         "Apr",
286         "May",
287         "Jun",
288         "Jul",
289         "Aug",
290         "Sep",
291         "Oct",
292         "Nov",
293         "Dec"
294 };
295
296 /* this routine checks the frame type from the cf structure */
297 void
298 dissect_packet(const u_char *pd, guint32 ts_secs, guint32 ts_usecs,
299   frame_data *fd, GtkTree *tree)
300 {
301         GtkWidget *fh_tree, *ti;
302         struct tm *tmp;
303         time_t then;
304
305         /* Put in frame header information. */
306         if (check_col(fd, COL_ABS_TIME)) {
307           if (timestamp_type == ABSOLUTE) {
308             then = fd->secs;
309             tmp = localtime(&then);
310             col_add_fstr(fd, COL_ABS_TIME, "%02d:%02d:%02d.%04ld",
311               tmp->tm_hour,
312               tmp->tm_min,                                                      
313               tmp->tm_sec,
314               (long)fd->usecs/100);
315           }
316         }
317         if (check_col(fd, COL_REL_TIME)) {
318             col_add_fstr(fd, COL_REL_TIME, "%d.%06d", ts_secs, ts_usecs);
319         }
320
321         if (tree) {
322           ti = add_item_to_tree(GTK_WIDGET(tree), 0, fd->cap_len,
323             "Frame (%d on wire, %d captured)",
324             fd->pkt_len, fd->cap_len);
325
326           fh_tree = gtk_tree_new();
327           add_subtree(ti, fh_tree, ETT_FRAME);
328           then = fd->secs;
329           tmp = localtime(&then);
330           add_item_to_tree(fh_tree, 0, 0,
331             "Frame arrived on %s %2d, %d %02d:%02d:%02d.%04ld",
332             mon_names[tmp->tm_mon],
333             tmp->tm_mday,
334             tmp->tm_year + 1900,
335             tmp->tm_hour,
336             tmp->tm_min,                                                      
337             tmp->tm_sec,
338             (long)fd->usecs/100);
339
340           add_item_to_tree(fh_tree, 0, 0, "Total frame length: %d bytes",
341             fd->pkt_len);
342           add_item_to_tree(fh_tree, 0, 0, "Capture frame length: %d bytes",
343             fd->cap_len);
344         }
345
346 #ifdef WITH_WIRETAP
347         switch (cf.lnk_t) {
348                 case WTAP_ENCAP_ETHERNET :
349                         dissect_eth(pd, fd, tree);
350                         break;
351                 case WTAP_ENCAP_FDDI :
352                         dissect_fddi(pd, fd, tree);
353                         break;
354                 case WTAP_ENCAP_TR :
355                         dissect_tr(pd, fd, tree);
356                         break;
357                 case WTAP_ENCAP_NONE :
358                         dissect_null(pd, fd, tree);
359                         break;
360                 case WTAP_ENCAP_PPP :
361                         dissect_ppp(pd, fd, tree);
362                         break;
363                 case WTAP_ENCAP_RAW_IP :
364                         dissect_raw(pd, fd, tree);
365                         break;
366         }
367 #else
368         switch (cf.lnk_t) {
369                 case DLT_EN10MB :
370                         dissect_eth(pd, fd, tree);
371                         break;
372                 case DLT_FDDI :
373                         dissect_fddi(pd, fd, tree);
374                         break;
375                 case DLT_IEEE802 :
376                         dissect_tr(pd, fd, tree);
377                         break;
378                 case DLT_NULL :
379                         dissect_null(pd, fd, tree);
380                         break;
381                 case DLT_PPP :
382                         dissect_ppp(pd, fd, tree);
383                         break;
384                 case DLT_RAW :
385                         dissect_raw(pd, fd, tree);
386                         break;
387         }
388 #endif
389 }