Initial revision
[obnox/wireshark/wip.git] / packet-ip.c
1 /* packet-ip.c
2  * Routines for IP and miscellaneous IP protocol packet disassembly
3  *
4  * Ethereal - Network traffic analyzer
5  * By Gerald Combs <gerald@zing.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * 
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <gtk/gtk.h>
29 #include <pcap.h>
30
31 #include <stdio.h>
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #ifdef HAVE_NETINET_IN_H
38 # include <netinet/in.h>
39 #endif
40
41 #include "ethereal.h"
42 #include "packet.h"
43 #include "etypes.h"
44 #include "resolv.h"
45
46 void
47 dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
48   e_ip       iph;
49   GtkWidget *ip_tree, *ti;
50   gchar      tos_str[32];
51
52   /* To do: check for runts, errs, etc. */
53   /* Avoids alignment problems on many architectures. */
54   memcpy(&iph, &pd[offset], sizeof(e_ip));
55   iph.ip_len = ntohs(iph.ip_len);
56   iph.ip_id  = ntohs(iph.ip_id);
57   iph.ip_off = ntohs(iph.ip_off);
58   iph.ip_sum = ntohs(iph.ip_sum);
59   
60   if (fd->win_info[0]) {
61     switch (iph.ip_p) {
62       case IP_PROTO_ICMP:
63       case IP_PROTO_IGMP:
64       case IP_PROTO_TCP:
65       case IP_PROTO_UDP:
66       case IP_PROTO_OSPF:
67         /* Names are set in the associated dissect_* routines */
68         break;
69       default:
70         strcpy(fd->win_info[3], "IP");
71         sprintf(fd->win_info[4], "Unknown IP protocol (%02x)", iph.ip_p);
72     }
73
74     strcpy(fd->win_info[1], get_hostname(iph.ip_src));
75     strcpy(fd->win_info[2], get_hostname(iph.ip_dst));
76   }
77   
78   iph.ip_tos = IPTOS_TOS(iph.ip_tos);
79   switch (iph.ip_tos) {
80     case IPTOS_NONE:
81       strcpy(tos_str, "None");
82       break;
83     case IPTOS_LOWDELAY:
84       strcpy(tos_str, "Minimize delay");
85       break;
86     case IPTOS_THROUGHPUT:
87       strcpy(tos_str, "Maximize throughput");
88       break;
89     case IPTOS_RELIABILITY:
90       strcpy(tos_str, "Maximize reliability");
91       break;
92     case IPTOS_LOWCOST:
93       strcpy(tos_str, "Minimize cost");
94       break;
95     default:
96       strcpy(tos_str, "Unknon.  Malformed?");
97       break;
98   }
99   
100   if (tree) {
101     ti = add_item_to_tree(GTK_WIDGET(tree), offset, (iph.ip_hl * 4),
102       "Internet Protocol");
103     ip_tree = gtk_tree_new();
104     add_subtree(ti, ip_tree, ETT_IP);
105     add_item_to_tree(ip_tree, offset,      1, "Version: %d", iph.ip_v);
106     add_item_to_tree(ip_tree, offset,      1, "Header length: %d", iph.ip_hl); 
107     add_item_to_tree(ip_tree, offset +  1, 1, "Type of service: 0x%02x (%s)",
108       iph.ip_tos, tos_str);
109     add_item_to_tree(ip_tree, offset +  2, 2, "Total length: %d", iph.ip_len);
110     add_item_to_tree(ip_tree, offset +  4, 2, "Identification: 0x%04x",
111       iph.ip_id);
112     /* To do: add flags */
113     add_item_to_tree(ip_tree, offset +  6, 2, "Fragment offset: %d",
114       iph.ip_off & 0x1fff);
115     add_item_to_tree(ip_tree, offset +  8, 1, "Time to live: %d",
116       iph.ip_ttl);
117     add_item_to_tree(ip_tree, offset +  9, 1, "Protocol: 0x%02x",
118       iph.ip_p);
119     add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x",
120       iph.ip_sum);
121     add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s",
122                      get_hostname(iph.ip_src));
123     add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s",
124                      get_hostname(iph.ip_dst));
125   }
126
127   offset += iph.ip_hl * 4;
128   switch (iph.ip_p) {
129     case IP_PROTO_ICMP:
130       dissect_icmp(pd, offset, fd, tree);
131      break;
132     case IP_PROTO_IGMP:
133       dissect_igmp(pd, offset, fd, tree);
134      break;
135     case IP_PROTO_TCP:
136       dissect_tcp(pd, offset, fd, tree);
137      break;
138    case IP_PROTO_UDP:
139       dissect_udp(pd, offset, fd, tree);
140       break;
141     case IP_PROTO_OSPF:
142       dissect_ospf(pd, offset, fd, tree);
143      break;
144   }
145 }
146
147
148 const gchar *unreach_str[] = {"Network unreachable",
149                               "Host unreachable",
150                               "Protocol unreachable",
151                               "Port unreachable",
152                               "Fragmentation needed",
153                               "Source route failed",
154                               "Administratively prohibited",
155                               "Network unreachable for TOS",
156                               "Host unreachable for TOS",
157                               "Communication administratively filtered",
158                               "Host precedence violation",
159                               "Precedence cutoff in effect"};
160
161 const gchar *redir_str[] = {"Redirect for network",
162                             "Redirect for host",
163                             "Redirect for TOS and network",
164                             "Redirect for TOS and host"};
165
166 const gchar *ttl_str[] = {"TTL equals 0 during transit",
167                           "TTL equals 0 during reassembly"};
168
169 const gchar *par_str[] = {"IP header bad", "Required option missing"};
170
171 void
172 dissect_icmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
173   e_icmp    *ih;
174   GtkWidget *icmp_tree, *ti;
175   guint16    cksum;
176   gchar      type_str[64], code_str[64] = "";
177
178   ih = (e_icmp *) &pd[offset];
179   /* To do: check for runts, errs, etc. */
180   cksum = ntohs(ih->icmp_cksum);
181   
182   switch (ih->icmp_type) {
183     case ICMP_ECHOREPLY:
184       strcpy(type_str, "Echo (ping) reply");
185       break;
186     case ICMP_UNREACH:
187       strcpy(type_str, "Destination unreachable");
188       if (ih->icmp_code < 12) {
189         sprintf(code_str, "(%s)", unreach_str[ih->icmp_code]);
190       } else {
191         strcpy(code_str, "(Unknown - error?)");
192       }
193       break;
194     case ICMP_SOURCEQUENCH:
195       strcpy(type_str, "Source quench (flow control)");
196       break;
197     case ICMP_REDIRECT:
198       strcpy(type_str, "Redirect");
199       if (ih->icmp_code < 4) {
200         sprintf(code_str, "(%s)", redir_str[ih->icmp_code]);
201       } else {
202         strcpy(code_str, "(Unknown - error?)");
203       }
204       break;
205     case ICMP_ECHO:
206       strcpy(type_str, "Echo (ping) request");
207       break;
208     case ICMP_TIMXCEED:
209       strcpy(type_str, "Time-to-live exceeded");
210       if (ih->icmp_code < 2) {
211         sprintf(code_str, "(%s)", ttl_str[ih->icmp_code]);
212       } else {
213         strcpy(code_str, "(Unknown - error?)");
214       }
215       break;
216     case ICMP_PARAMPROB:
217       strcpy(type_str, "Parameter problem");
218       if (ih->icmp_code < 2) {
219         sprintf(code_str, "(%s)", par_str[ih->icmp_code]);
220       } else {
221         strcpy(code_str, "(Unknown - error?)");
222       }
223       break;
224     case ICMP_TSTAMP:
225       strcpy(type_str, "Timestamp request");
226       break;
227     case ICMP_TSTAMPREPLY:
228       strcpy(type_str, "Timestamp reply");
229       break;
230     case ICMP_MASKREQ:
231       strcpy(type_str, "Address mask request");
232       break;
233     case ICMP_MASKREPLY:
234       strcpy(type_str, "Address mask reply");
235       break;
236     default:
237       strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
238   }
239
240   if (fd->win_info[0]) {    
241     strcpy(fd->win_info[3], "ICMP");
242     strcpy(fd->win_info[4], type_str);
243   }
244   
245   if (tree) {
246     ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
247       "Internet Control Message Protocol");
248     icmp_tree = gtk_tree_new();
249     add_subtree(ti, icmp_tree, ETT_ICMP);
250     add_item_to_tree(icmp_tree, offset,      1, "Type: %d (%s)",
251       ih->icmp_type, type_str);
252     add_item_to_tree(icmp_tree, offset +  1, 1, "Code: %d %s",
253       ih->icmp_code, code_str);
254     add_item_to_tree(icmp_tree, offset +  2, 2, "Checksum: 0x%04x",
255       ih->icmp_cksum);
256   }
257 }
258
259 void
260 dissect_igmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
261   e_igmp    *ih;
262   GtkWidget *igmp_tree, *ti;
263   guint16    cksum;
264   gchar      type_str[64] = "";
265
266   ih = (e_igmp *) &pd[offset];
267   /* To do: check for runts, errs, etc. */
268   cksum = ntohs(ih->igmp_cksum);
269   
270   switch (ih->igmp_t) {
271     case IGMP_M_QRY:
272       strcpy(type_str, "Router query");
273       break;
274     case IGMP_V1_M_RPT:
275       strcpy(type_str, "Host response (v1)");
276       break;
277     case IGMP_V2_LV_GRP:
278       strcpy(type_str, "Leave group (v2)");
279       break;
280     case IGMP_DVMRP:
281       strcpy(type_str, "DVMRP");
282       break;
283     case IGMP_PIM:
284       strcpy(type_str, "PIM");
285       break;
286     case IGMP_V2_M_RPT:
287       strcpy(type_str, "Host reponse (v2)");
288       break;
289     case IGMP_MTRC_RESP:
290       strcpy(type_str, "Traceroute response");
291       break;
292     case IGMP_MTRC:
293       strcpy(type_str, "Traceroute message");
294       break;
295     default:
296       strcpy(type_str, "Unknown IGMP");
297   }
298
299   if (fd->win_info[0]) {    
300     strcpy(fd->win_info[3], "IGMP");
301   }
302   
303   if (tree) {
304     ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
305       "Internet Group Management Protocol");
306     igmp_tree = gtk_tree_new();
307     add_subtree(ti, igmp_tree, ETT_IGMP);
308     add_item_to_tree(igmp_tree, offset,     1, "Version: %d",
309       ih->igmp_v);
310     add_item_to_tree(igmp_tree, offset    , 1, "Type: %d (%s)",
311       ih->igmp_t, type_str);
312     add_item_to_tree(igmp_tree, offset + 1, 1, "Unused: 0x%02x",
313       ih->igmp_unused);
314     add_item_to_tree(igmp_tree, offset + 2, 2, "Checksum: 0x%04x",
315       ih->igmp_cksum);
316     add_item_to_tree(igmp_tree, offset + 4, 4, "Group address: %s",
317       ip_to_str((guint8 *) &ih->igmp_gaddr));
318   }
319 }