Decode more stuff in an ICMP packet.
[obnox/wireshark/wip.git] / packet-ip.c
1 /* packet-ip.c
2  * Routines for IP and miscellaneous IP protocol packet disassembly
3  *
4  * $Id: packet-ip.c,v 1.17 1999/03/09 02:52:37 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 #include <gtk/gtk.h>
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 "ethereal.h"
43 #include "packet.h"
44 #include "etypes.h"
45 #include "resolv.h"
46 #include "util.h"
47
48 extern packet_info pi;
49
50 void
51 capture_ip(const u_char *pd, int offset, guint32 cap_len, packet_counts *ld) {
52   switch (pd[offset + 9]) {
53     case IP_PROTO_TCP:
54       ld->tcp++;
55       break;
56     case IP_PROTO_UDP:
57       ld->udp++;
58       break;
59     case IP_PROTO_OSPF:
60       ld->ospf++;
61       break;
62     default:
63       ld->other++;
64   }
65 }
66
67 static void
68 dissect_ipopt_security(GtkWidget *opt_tree, const char *name,
69     const u_char *opd, int offset, guint optlen)
70 {
71   GtkWidget *field_tree = NULL, *tf;
72   guint      val;
73   static const value_string secl_vals[] = {
74     {IPSEC_UNCLASSIFIED, "Unclassified"},
75     {IPSEC_CONFIDENTIAL, "Confidential"},
76     {IPSEC_EFTO,         "EFTO"        },
77     {IPSEC_MMMM,         "MMMM"        },
78     {IPSEC_RESTRICTED,   "Restricted"  },
79     {IPSEC_SECRET,       "Secret"      },
80     {IPSEC_TOPSECRET,    "Top secret"  },
81     {IPSEC_RESERVED1,    "Reserved"    },
82     {IPSEC_RESERVED2,    "Reserved"    },
83     {IPSEC_RESERVED3,    "Reserved"    },
84     {IPSEC_RESERVED4,    "Reserved"    },
85     {IPSEC_RESERVED5,    "Reserved"    },
86     {IPSEC_RESERVED6,    "Reserved"    },
87     {IPSEC_RESERVED7,    "Reserved"    },
88     {IPSEC_RESERVED8,    "Reserved"    },
89     {0,                  NULL          } };
90
91   tf = add_item_to_tree(opt_tree, offset,      optlen, "%s:", name);
92   field_tree = gtk_tree_new();
93   add_subtree(tf, field_tree, ETT_IP_OPTION_SEC);
94   offset += 2;
95
96   val = pntohs(opd);
97   add_item_to_tree(field_tree, offset,       2,
98               "Security: %s", val_to_str(val, secl_vals, "Unknown (0x%x)"));
99   offset += 2;
100   opd += 2;
101
102   val = pntohs(opd);
103   add_item_to_tree(field_tree, offset,         2,
104               "Compartments: %d", val);
105   offset += 2;
106   opd += 2;
107
108   add_item_to_tree(field_tree, offset,         2,
109               "Handling restrictions: %c%c", opd[0], opd[1]);
110   offset += 2;
111   opd += 2;
112
113   add_item_to_tree(field_tree, offset,         3,
114               "Transmission control code: %c%c%c", opd[0], opd[1], opd[2]);
115 }
116
117 static void
118 dissect_ipopt_route(GtkWidget *opt_tree, const char *name,
119     const u_char *opd, int offset, guint optlen)
120 {
121   GtkWidget *field_tree = NULL, *tf;
122   int ptr;
123   int optoffset = 0;
124   struct in_addr addr;
125
126   tf = add_item_to_tree(opt_tree, offset,      optlen, "%s (%d bytes)", name,
127               optlen);
128   field_tree = gtk_tree_new();
129   add_subtree(tf, field_tree, ETT_IP_OPTION_ROUTE);
130
131   optoffset += 2;       /* skip past type and length */
132   optlen -= 2;          /* subtract size of type and length */
133
134   ptr = *opd;
135   add_item_to_tree(field_tree, offset + optoffset, 1,
136               "Pointer: %d%s", ptr,
137               ((ptr < 4) ? " (points before first address)" :
138                ((ptr & 3) ? " (points to middle of address)" : "")));
139   optoffset++;
140   opd++;
141   optlen--;
142   ptr--;        /* ptr is 1-origin */
143
144   while (optlen > 0) {
145     if (optlen < 4) {
146       add_item_to_tree(field_tree, offset,      optlen,
147         "(suboption would go past end of option)");
148       break;
149     }
150
151     /* Avoids alignment problems on many architectures. */
152     memcpy((char *)&addr, (char *)opd, sizeof(addr));
153
154     add_item_to_tree(field_tree, offset + optoffset, 4,
155               "%s%s",
156               ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
157               ((optoffset == ptr) ? " <- (current)" : ""));
158     optoffset += 4;
159     opd += 4;
160     optlen -= 4;
161   }
162 }
163
164 static void
165 dissect_ipopt_sid(GtkWidget *opt_tree, const char *name, const u_char *opd,
166     int offset, guint optlen)
167 {
168   add_item_to_tree(opt_tree, offset,      optlen,
169     "%s: %d", name, pntohs(opd));
170   return;
171 }
172
173 static void
174 dissect_ipopt_timestamp(GtkWidget *opt_tree, const char *name, const u_char *opd,
175     int offset, guint optlen)
176 {
177   GtkWidget *field_tree = NULL, *tf;
178   int        ptr;
179   int        optoffset = 0;
180   int        flg;
181   static const value_string flag_vals[] = {
182     {IPOPT_TS_TSONLY,    "Time stamps only"                      },
183     {IPOPT_TS_TSANDADDR, "Time stamp and address"                },
184     {IPOPT_TS_PRESPEC,   "Time stamps for prespecified addresses"},
185     {0,                  NULL                                    } };
186
187   struct in_addr addr;
188   guint ts;
189
190   tf = add_item_to_tree(opt_tree, offset,      optlen, "%s:", name);
191   field_tree = gtk_tree_new();
192   add_subtree(tf, field_tree, ETT_IP_OPTION_TIMESTAMP);
193
194   optoffset += 2;       /* skip past type and length */
195   optlen -= 2;          /* subtract size of type and length */
196
197   ptr = *opd;
198   add_item_to_tree(field_tree, offset + optoffset, 1,
199               "Pointer: %d%s", ptr,
200               ((ptr < 5) ? " (points before first address)" :
201                (((ptr - 1) & 3) ? " (points to middle of address)" : "")));
202   optoffset++;
203   opd++;
204   optlen--;
205   ptr--;        /* ptr is 1-origin */
206
207   flg = *opd;
208   add_item_to_tree(field_tree, offset + optoffset,   1,
209         "Overflow: %d", flg >> 4);
210   flg &= 0xF;
211   add_item_to_tree(field_tree, offset + optoffset, 1,
212         "Flag: %s", val_to_str(flg, flag_vals, "Unknown (0x%x)"));
213   optoffset++;
214   opd++;
215   optlen--;
216
217   while (optlen > 0) {
218     if (flg == IPOPT_TS_TSANDADDR) {
219       if (optlen < 4) {
220         add_item_to_tree(field_tree, offset + optoffset, optlen,
221           "(suboption would go past end of option)");
222         break;
223       }
224       /* XXX - check whether it goes past end of packet */
225       ts = pntohl(opd);
226       opd += 4;
227       optlen -= 4;
228       if (optlen < 4) {
229         add_item_to_tree(field_tree, offset + optoffset, optlen,
230           "(suboption would go past end of option)");
231         break;
232       }
233       /* XXX - check whether it goes past end of packet */
234       memcpy((char *)&addr, (char *)opd, sizeof(addr));
235       opd += 4;
236       optlen -= 4;
237       add_item_to_tree(field_tree, offset,      8,
238           "Address = %s, time stamp = %u",
239           ((addr.s_addr == 0) ? "-" :  (char *)get_hostname(addr.s_addr)),
240           ts);
241       optoffset += 8;
242     } else {
243       if (optlen < 4) {
244         add_item_to_tree(field_tree, offset + optoffset, optlen,
245           "(suboption would go past end of option)");
246         break;
247       }
248       /* XXX - check whether it goes past end of packet */
249       ts = pntohl(opd);
250       opd += 4;
251       optlen -= 4;
252       add_item_to_tree(field_tree, offset + optoffset, 4,
253           "Time stamp = %u", ts);
254       optoffset += 4;
255     }
256   }
257 }
258
259 static ip_tcp_opt ipopts[] = {
260   {
261     IPOPT_END,
262     "EOL",
263     NO_LENGTH,
264     0,
265     NULL,
266   },
267   {
268     IPOPT_NOOP,
269     "NOP",
270     NO_LENGTH,
271     0,
272     NULL,
273   },
274   {
275     IPOPT_SEC,
276     "Security",
277     FIXED_LENGTH,
278     IPOLEN_SEC,
279     dissect_ipopt_security
280   },
281   {
282     IPOPT_SSRR,
283     "Strict source route",
284     VARIABLE_LENGTH,
285     IPOLEN_SSRR_MIN,
286     dissect_ipopt_route
287   },
288   {
289     IPOPT_LSRR,
290     "Loose source route",
291     VARIABLE_LENGTH,
292     IPOLEN_LSRR_MIN,
293     dissect_ipopt_route
294   },
295   {
296     IPOPT_RR,
297     "Record route",
298     VARIABLE_LENGTH,
299     IPOLEN_RR_MIN,
300     dissect_ipopt_route
301   },
302   {
303     IPOPT_SID,
304     "Stream identifier",
305     FIXED_LENGTH,
306     IPOLEN_SID,
307     dissect_ipopt_sid
308   },
309   {
310     IPOPT_TIMESTAMP,
311     "Time stamp",
312     VARIABLE_LENGTH,
313     IPOLEN_TIMESTAMP_MIN,
314     dissect_ipopt_timestamp
315   }
316 };
317
318 #define N_IP_OPTS       (sizeof ipopts / sizeof ipopts[0])
319
320 /* Dissect the IP or TCP options in a packet. */
321 void
322 dissect_ip_tcp_options(GtkWidget *opt_tree, const u_char *opd, int offset,
323     guint length, ip_tcp_opt *opttab, int nopts, int eol)
324 {
325   u_char      opt;
326   ip_tcp_opt *optp;
327   guint       len;
328
329   while (length > 0) {
330     opt = *opd++;
331     for (optp = &opttab[0]; optp < &opttab[nopts]; optp++) {
332       if (optp->optcode == opt)
333         break;
334     }
335     if (optp == &opttab[nopts]) {
336       add_item_to_tree(opt_tree, offset,      1, "Unknown");
337       /* We don't know how long this option is, so we don't know how much
338          of it to skip, so we just bail. */
339       return;
340     }
341     --length;      /* account for type byte */
342     if (optp->len_type != NO_LENGTH) {
343       /* Option has a length. Is it in the packet? */
344       if (length == 0) {
345         /* Bogus - packet must at least include option code byte and
346            length byte! */
347         add_item_to_tree(opt_tree, offset,      1,
348               "%s (length byte past end of header)", optp->name);
349         return;
350       }
351       len = *opd++;  /* total including type, len */
352       --length;    /* account for length byte */
353       if (len < 2) {
354         /* Bogus - option length is too short to include option code and
355            option length. */
356         add_item_to_tree(opt_tree, offset,      2,
357               "%s (with too-short option length = %u bytes)", optp->name, 2);
358         return;
359       } else if (len - 2 > length) {
360         /* Bogus - option goes past the end of the header. */
361         add_item_to_tree(opt_tree, offset,      length,
362               "%s (option goes past end of header)", optp->name);
363         return;
364       } else if (optp->len_type == FIXED_LENGTH && len != optp->optlen) {
365         /* Bogus - option length isn't what it's supposed to be for this
366            option. */
367         add_item_to_tree(opt_tree, offset,      len,
368               "%s (with option length = %u bytes; should be %u)", optp->name,
369               len, optp->optlen);
370         return;
371       } else if (optp->len_type == VARIABLE_LENGTH && len < optp->optlen) {
372         /* Bogus - option length is less than what it's supposed to be for
373            this option. */
374         add_item_to_tree(opt_tree, offset,      len,
375               "%s (with option length = %u bytes; should be >= %u)", optp->name,
376               len, optp->optlen);
377         return;
378       } else {
379         if (optp->dissect != NULL) {
380           /* Option has a dissector. */
381           (*optp->dissect)(opt_tree, optp->name, opd, offset, len);
382         } else {
383           /* Option has no data, hence no dissector. */
384           add_item_to_tree(opt_tree, offset,      len, "%s", optp->name);
385         }
386         len -= 2;       /* subtract size of type and length */
387         offset += 2 + len;
388       }
389       opd += len;
390       length -= len;
391     } else {
392       add_item_to_tree(opt_tree, offset,      1, "%s", optp->name);
393       offset += 1;
394     }
395     if (opt == eol)
396       break;
397   }
398 }
399
400 void
401 dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
402   e_ip       iph;
403   GtkWidget *ip_tree, *ti, *field_tree, *tf;
404   gchar      tos_str[32];
405   guint      hlen, optlen;
406   static const value_string proto_vals[] = { {IP_PROTO_ICMP, "ICMP"},
407                                              {IP_PROTO_IGMP, "IGMP"},
408                                              {IP_PROTO_TCP,  "TCP" },
409                                              {IP_PROTO_UDP,  "UDP" },
410                                              {IP_PROTO_OSPF, "OSPF"},
411                                              {0,             NULL  } };
412   static const value_string precedence_vals[] = {
413                   { IPTOS_PREC_ROUTINE,         "routine"              },
414                   { IPTOS_PREC_PRIORITY,        "priority"             },
415                   { IPTOS_PREC_IMMEDIATE,       "immediate"            },
416                   { IPTOS_PREC_FLASH,           "flash"                },
417                   { IPTOS_PREC_FLASHOVERRIDE,   "flash override"       },
418                   { IPTOS_PREC_CRITIC_ECP,      "CRITIC/ECP"           },
419                   { IPTOS_PREC_INTERNETCONTROL, "internetwork control" },
420                   { IPTOS_PREC_NETCONTROL,      "network control"      },
421                   { 0,                          NULL                   } };
422
423   /* To do: check for runts, errs, etc. */
424   /* Avoids alignment problems on many architectures. */
425   memcpy(&iph, &pd[offset], sizeof(e_ip));
426   iph.ip_len = ntohs(iph.ip_len);
427   iph.ip_id  = ntohs(iph.ip_id);
428   iph.ip_off = ntohs(iph.ip_off);
429   iph.ip_sum = ntohs(iph.ip_sum);
430
431   hlen = lo_nibble(iph.ip_v_hl) * 4;    /* IP header length, in bytes */
432   
433   switch (iph.ip_p) {
434     case IP_PROTO_ICMP:
435     case IP_PROTO_IGMP:
436     case IP_PROTO_TCP:
437     case IP_PROTO_UDP:
438     case IP_PROTO_OSPF:
439       /* Names are set in the associated dissect_* routines */
440       break;
441     default:
442       if (check_col(fd, COL_PROTOCOL))
443         col_add_str(fd, COL_PROTOCOL, "IP");
444       if (check_col(fd, COL_INFO))
445         col_add_fstr(fd, COL_INFO, "Unknown IP protocol (%02x)", iph.ip_p);
446   }
447
448   if (check_col(fd, COL_RES_NET_SRC))
449     col_add_str(fd, COL_RES_NET_SRC, get_hostname(iph.ip_src));
450   if (check_col(fd, COL_UNRES_NET_SRC))
451     col_add_str(fd, COL_UNRES_NET_SRC, ip_to_str((guint8 *) &iph.ip_src));
452   if (check_col(fd, COL_RES_NET_DST))
453     col_add_str(fd, COL_RES_NET_DST, get_hostname(iph.ip_dst));
454   if (check_col(fd, COL_UNRES_NET_DST))
455     col_add_str(fd, COL_UNRES_NET_DST, ip_to_str((guint8 *) &iph.ip_dst));
456   
457   iph.ip_tos = IPTOS_TOS(iph.ip_tos);
458   switch (iph.ip_tos) {
459     case IPTOS_NONE:
460       strcpy(tos_str, "None");
461       break;
462     case IPTOS_LOWCOST:
463       strcpy(tos_str, "Minimize cost");
464       break;
465     case IPTOS_RELIABILITY:
466       strcpy(tos_str, "Maximize reliability");
467       break;
468     case IPTOS_THROUGHPUT:
469       strcpy(tos_str, "Maximize throughput");
470       break;
471     case IPTOS_LOWDELAY:
472       strcpy(tos_str, "Minimize delay");
473       break;
474     case IPTOS_SECURITY:
475       strcpy(tos_str, "Maximize security");
476       break;
477     default:
478       strcpy(tos_str, "Unknown.  Malformed?");
479       break;
480   }
481   
482   if (tree) {
483     ti = add_item_to_tree(GTK_WIDGET(tree), offset, hlen, "Internet Protocol");
484     ip_tree = gtk_tree_new();
485     add_subtree(ti, ip_tree, ETT_IP);
486     add_item_to_tree(ip_tree, offset,      1, "Version: %d", hi_nibble(iph.ip_v_hl));
487     add_item_to_tree(ip_tree, offset,      1, "Header length: %d bytes", hlen); 
488     tf = add_item_to_tree(ip_tree, offset +  1, 1, "Type of service: 0x%02x (%s)",
489       iph.ip_tos, tos_str);
490     field_tree = gtk_tree_new();
491     add_subtree(tf, field_tree, ETT_IP_TOS);
492     add_item_to_tree(field_tree, offset + 1, 1, "%s",
493        decode_enumerated_bitfield(iph.ip_tos, IPTOS_PREC_MASK,
494                                    sizeof (iph.ip_tos)*8, precedence_vals,
495                                    "%s precedence"));
496     add_item_to_tree(field_tree, offset + 1, 1, "%s",
497        decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWDELAY,
498                 sizeof (iph.ip_tos)*8, "low delay", "normal delay"));
499     add_item_to_tree(field_tree, offset + 1, 1, "%s",
500        decode_boolean_bitfield(iph.ip_tos, IPTOS_THROUGHPUT,
501             sizeof (iph.ip_tos)*8, "high throughput", "normal throughput"));
502     add_item_to_tree(field_tree, offset + 1, 1, "%s",
503        decode_boolean_bitfield(iph.ip_tos, IPTOS_RELIABILITY,
504             sizeof (iph.ip_tos)*8, "high reliability", "normal reliability"));
505     add_item_to_tree(field_tree, offset + 1, 1, "%s",
506        decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWCOST,
507             sizeof (iph.ip_tos)*8, "low cost", "normal cost"));
508     add_item_to_tree(ip_tree, offset +  2, 2, "Total length: %d", iph.ip_len);
509     add_item_to_tree(ip_tree, offset +  4, 2, "Identification: 0x%04x",
510       iph.ip_id);
511     tf = add_item_to_tree(ip_tree, offset +  6, 2, "Flags: 0x%x",
512       (iph.ip_off & (IP_DF|IP_MF)) >> 12);
513     field_tree = gtk_tree_new();
514     add_subtree(tf, field_tree, ETT_IP_OFF);
515     add_item_to_tree(field_tree, offset + 6, 2, "%s",
516       decode_boolean_bitfield(iph.ip_off >> 8, IP_DF >> 8, 8, "don't fragment",
517                                            "may fragment"));
518     add_item_to_tree(field_tree, offset + 6, 2, "%s",
519       decode_boolean_bitfield(iph.ip_off >> 8, IP_MF >> 8, 8, "more fragments",
520                                            "last fragment"));
521     add_item_to_tree(ip_tree, offset +  6, 2, "Fragment offset: %d",
522       iph.ip_off & IP_OFFSET);
523     add_item_to_tree(ip_tree, offset +  8, 1, "Time to live: %d",
524       iph.ip_ttl);
525     add_item_to_tree(ip_tree, offset +  9, 1, "Protocol: %s",
526       val_to_str(iph.ip_p, proto_vals, "Unknown (%x)"));
527     add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x",
528       iph.ip_sum);
529     add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s (%s)",
530                      get_hostname(iph.ip_src),
531                      ip_to_str((guint8 *) &iph.ip_src));
532     add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s (%s)",
533                      get_hostname(iph.ip_dst),
534                      ip_to_str((guint8 *) &iph.ip_dst));
535
536     /* Decode IP options, if any. */
537     if (hlen > sizeof (e_ip)) {
538       /* There's more than just the fixed-length header.  Decode the
539          options. */
540       optlen = hlen - sizeof (e_ip);    /* length of options, in bytes */
541       tf = add_item_to_tree(ip_tree, offset +  20, optlen,
542         "Options: (%d bytes)", optlen);
543       field_tree = gtk_tree_new();
544       add_subtree(tf, field_tree, ETT_IP_OPTIONS);
545       dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen,
546          ipopts, N_IP_OPTS, IPOPT_END);
547     }
548   }
549
550   pi.srcip = ip_to_str( (guint8 *) &iph.ip_src);
551   pi.destip = ip_to_str( (guint8 *) &iph.ip_dst);
552   pi.ipproto = iph.ip_p;
553   pi.iplen = iph.ip_len;
554   pi.iphdrlen = lo_nibble(iph.ip_v_hl);
555   pi.ip_src = iph.ip_src;
556
557   offset += hlen;
558   switch (iph.ip_p) {
559     case IP_PROTO_ICMP:
560       dissect_icmp(pd, offset, fd, tree);
561      break;
562     case IP_PROTO_IGMP:
563       dissect_igmp(pd, offset, fd, tree);
564      break;
565     case IP_PROTO_TCP:
566       dissect_tcp(pd, offset, fd, tree);
567      break;
568    case IP_PROTO_UDP:
569       dissect_udp(pd, offset, fd, tree);
570       break;
571     case IP_PROTO_OSPF:
572       dissect_ospf(pd, offset, fd, tree);
573      break;
574   }
575 }
576
577
578 static const gchar *unreach_str[] = {"Network unreachable",
579                                      "Host unreachable",
580                                      "Protocol unreachable",
581                                      "Port unreachable",
582                                      "Fragmentation needed",
583                                      "Source route failed",
584                                      "Administratively prohibited",
585                                      "Network unreachable for TOS",
586                                      "Host unreachable for TOS",
587                                      "Communication administratively filtered",
588                                      "Host precedence violation",
589                                      "Precedence cutoff in effect"};
590                                      
591 #define N_UNREACH       (sizeof unreach_str / sizeof unreach_str[0])
592
593 static const gchar *redir_str[] = {"Redirect for network",
594                                    "Redirect for host",
595                                    "Redirect for TOS and network",
596                                    "Redirect for TOS and host"};
597
598 #define N_REDIRECT      (sizeof redir_str / sizeof redir_str[0])
599
600 static const gchar *ttl_str[] = {"TTL equals 0 during transit",
601                                  "TTL equals 0 during reassembly"};
602                                  
603 #define N_TIMXCEED      (sizeof ttl_str / sizeof ttl_str[0])
604
605 static const gchar *par_str[] = {"IP header bad", "Required option missing"};
606
607 #define N_PARAMPROB     (sizeof par_str / sizeof par_str[0])
608
609 void
610 dissect_icmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
611   e_icmp     ih;
612   GtkWidget *icmp_tree, *ti;
613   guint16    cksum;
614   gchar      type_str[64], code_str[64] = "";
615
616   /* Avoids alignment problems on many architectures. */
617   memcpy(&ih, &pd[offset], sizeof(e_icmp));
618   /* To do: check for runts, errs, etc. */
619   cksum = ntohs(ih.icmp_cksum);
620   
621   switch (ih.icmp_type) {
622     case ICMP_ECHOREPLY:
623       strcpy(type_str, "Echo (ping) reply");
624       break;
625     case ICMP_UNREACH:
626       strcpy(type_str, "Destination unreachable");
627       if (ih.icmp_code < N_UNREACH) {
628         sprintf(code_str, "(%s)", unreach_str[ih.icmp_code]);
629       } else {
630         strcpy(code_str, "(Unknown - error?)");
631       }
632       break;
633     case ICMP_SOURCEQUENCH:
634       strcpy(type_str, "Source quench (flow control)");
635       break;
636     case ICMP_REDIRECT:
637       strcpy(type_str, "Redirect");
638       if (ih.icmp_code < N_REDIRECT) {
639         sprintf(code_str, "(%s)", redir_str[ih.icmp_code]);
640       } else {
641         strcpy(code_str, "(Unknown - error?)");
642       }
643       break;
644     case ICMP_ECHO:
645       strcpy(type_str, "Echo (ping) request");
646       break;
647     case ICMP_TIMXCEED:
648       strcpy(type_str, "Time-to-live exceeded");
649       if (ih.icmp_code < N_TIMXCEED) {
650         sprintf(code_str, "(%s)", ttl_str[ih.icmp_code]);
651       } else {
652         strcpy(code_str, "(Unknown - error?)");
653       }
654       break;
655     case ICMP_PARAMPROB:
656       strcpy(type_str, "Parameter problem");
657       if (ih.icmp_code < N_PARAMPROB) {
658         sprintf(code_str, "(%s)", par_str[ih.icmp_code]);
659       } else {
660         strcpy(code_str, "(Unknown - error?)");
661       }
662       break;
663     case ICMP_TSTAMP:
664       strcpy(type_str, "Timestamp request");
665       break;
666     case ICMP_TSTAMPREPLY:
667       strcpy(type_str, "Timestamp reply");
668       break;
669     case ICMP_IREQ:
670       strcpy(type_str, "Information request");
671       break;
672     case ICMP_IREQREPLY:
673       strcpy(type_str, "Information reply");
674       break;
675     case ICMP_MASKREQ:
676       strcpy(type_str, "Address mask request");
677       break;
678     case ICMP_MASKREPLY:
679       strcpy(type_str, "Address mask reply");
680       break;
681     default:
682       strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
683   }
684
685   if (check_col(fd, COL_PROTOCOL))
686     col_add_str(fd, COL_PROTOCOL, "ICMP");
687   if (check_col(fd, COL_INFO))
688     col_add_str(fd, COL_INFO, type_str);
689   
690   if (tree) {
691     ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
692       "Internet Control Message Protocol");
693     icmp_tree = gtk_tree_new();
694     add_subtree(ti, icmp_tree, ETT_ICMP);
695     add_item_to_tree(icmp_tree, offset,      1, "Type: %d (%s)",
696       ih.icmp_type, type_str);
697     add_item_to_tree(icmp_tree, offset +  1, 1, "Code: %d %s",
698       ih.icmp_code, code_str);
699     add_item_to_tree(icmp_tree, offset +  2, 2, "Checksum: 0x%04x",
700       ih.icmp_cksum);
701
702     /* Decode the second 4 byte of the packet. */
703     switch (ih.icmp_type) {
704       case ICMP_ECHOREPLY:
705       case ICMP_ECHO:
706       case ICMP_TSTAMP:
707       case ICMP_TSTAMPREPLY:
708       case ICMP_IREQ:
709       case ICMP_IREQREPLY:
710       case ICMP_MASKREQ:
711       case ICMP_MASKREPLY:
712         add_item_to_tree(icmp_tree, offset +  4, 2, "Identifier: 0x%04x",
713           pntohs(&pd[offset +  4]));
714         add_item_to_tree(icmp_tree, offset +  6, 2, "Sequence number: %u",
715           pntohs(&pd[offset +  6]));
716         break;
717
718       case ICMP_PARAMPROB:
719         add_item_to_tree(icmp_tree, offset +  4, 1, "Pointer: %u",
720           pd[offset +  4]);
721         break;
722
723       case ICMP_REDIRECT:
724         add_item_to_tree(icmp_tree, offset +  4, 4, "Gateway address: %s",
725           ip_to_str((guint8 *)&pd[offset +  4]));
726         break;
727     }
728
729     /* Decode the additional information in the packet.  */
730     switch (ih.icmp_type) {
731       case ICMP_UNREACH:
732       case ICMP_TIMXCEED:
733       case ICMP_PARAMPROB:
734       case ICMP_SOURCEQUENCH:
735       case ICMP_REDIRECT:
736         /* Decode the IP header and first 64 bits of data from the
737            original datagram.
738
739            XXX - for now, just display it as data; not all dissection
740            routines can handle a short packet without exploding. */
741         dissect_data(pd, offset + 8, fd, (GtkTree *)icmp_tree);
742         break;
743
744       case ICMP_ECHOREPLY:
745       case ICMP_ECHO:
746         dissect_data(pd, offset + 8, fd, (GtkTree *)icmp_tree);
747         break;
748
749       case ICMP_TSTAMP:
750       case ICMP_TSTAMPREPLY:
751         add_item_to_tree(icmp_tree, offset +  8, 4, "Originate timestamp: %u",
752           pntohl(&pd[offset +  8]));
753         add_item_to_tree(icmp_tree, offset + 12, 4, "Originate timestamp: %u",
754           pntohl(&pd[offset + 12]));
755         add_item_to_tree(icmp_tree, offset + 16, 4, "Receive timestamp: %u",
756           pntohl(&pd[offset + 16]));
757         add_item_to_tree(icmp_tree, offset + 20, 4, "Transmit timestamp: %u",
758           pntohl(&pd[offset + 20]));
759         break;
760
761     case ICMP_MASKREQ:
762     case ICMP_MASKREPLY:
763         add_item_to_tree(icmp_tree, offset +  8, 4, "Address mask: %s (0x%8x)",
764           ip_to_str((guint8 *)&pd[offset +  8]), pntohl(&pd[offset +  8]));
765         break;
766     }
767   }
768 }
769
770 void
771 dissect_igmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
772   e_igmp     ih;
773   GtkWidget *igmp_tree, *ti;
774   guint16    cksum;
775   gchar      type_str[64] = "";
776
777   /* Avoids alignment problems on many architectures. */
778   memcpy(&ih, &pd[offset], sizeof(e_igmp));
779   /* To do: check for runts, errs, etc. */
780   cksum = ntohs(ih.igmp_cksum);
781   
782   switch (lo_nibble(ih.igmp_v_t)) {
783     case IGMP_M_QRY:
784       strcpy(type_str, "Router query");
785       break;
786     case IGMP_V1_M_RPT:
787       strcpy(type_str, "Host response (v1)");
788       break;
789     case IGMP_V2_LV_GRP:
790       strcpy(type_str, "Leave group (v2)");
791       break;
792     case IGMP_DVMRP:
793       strcpy(type_str, "DVMRP");
794       break;
795     case IGMP_PIM:
796       strcpy(type_str, "PIM");
797       break;
798     case IGMP_V2_M_RPT:
799       strcpy(type_str, "Host reponse (v2)");
800       break;
801     case IGMP_MTRC_RESP:
802       strcpy(type_str, "Traceroute response");
803       break;
804     case IGMP_MTRC:
805       strcpy(type_str, "Traceroute message");
806       break;
807     default:
808       strcpy(type_str, "Unknown IGMP");
809   }
810
811   if (check_col(fd, COL_PROTOCOL))
812     col_add_str(fd, COL_PROTOCOL, "IGMP");
813   if (check_col(fd, COL_INFO))
814     col_add_str(fd, COL_INFO, type_str);
815   
816   if (tree) {
817     ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
818       "Internet Group Management Protocol");
819     igmp_tree = gtk_tree_new();
820     add_subtree(ti, igmp_tree, ETT_IGMP);
821     add_item_to_tree(igmp_tree, offset,     1, "Version: %d",
822       hi_nibble(ih.igmp_v_t));
823     add_item_to_tree(igmp_tree, offset    , 1, "Type: %d (%s)",
824       lo_nibble(ih.igmp_v_t), type_str);
825     add_item_to_tree(igmp_tree, offset + 1, 1, "Unused: 0x%02x",
826       ih.igmp_unused);
827     add_item_to_tree(igmp_tree, offset + 2, 2, "Checksum: 0x%04x",
828       ih.igmp_cksum);
829     add_item_to_tree(igmp_tree, offset + 4, 4, "Group address: %s",
830       ip_to_str((guint8 *) &ih.igmp_gaddr));
831   }
832 }