Created a new protocol tree implementation and a new display filter
[obnox/wireshark/wip.git] / packet-udp.c
1 /* packet-udp.c
2  * Routines for UDP packet disassembly
3  *
4  * $Id: packet-udp.c,v 1.19 1999/07/07 22:51:57 gram Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * Richard Sharpe, 13-Feb-1999, added dispatch table support and 
11  *                              support for tftp.
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 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
35
36 #ifdef HAVE_NETINET_IN_H
37 # include <netinet/in.h>
38 #endif
39
40 #include <stdio.h>
41 #include <stdlib.h>
42
43 #include <glib.h>
44 #include "packet.h"
45 #include "resolv.h"
46
47 extern packet_info pi;
48
49 /* UDP structs and definitions */
50
51 typedef struct _e_udphdr {
52   guint16 uh_sport;
53   guint16 uh_dport;
54   guint16 uh_ulen;
55   guint16 uh_sum;
56 } e_udphdr;
57
58 /* UDP Ports -> should go in packet-udp.h */
59
60 #define UDP_PORT_DNS     53
61 #define UDP_PORT_BOOTPS  67
62 #define UDP_PORT_TFTP    69
63 #define UDP_PORT_IPX    213
64 #define UDP_PORT_NBNS   137
65 #define UDP_PORT_NBDGM  138
66 #define UDP_PORT_SNMP   161
67 #define UDP_PORT_ISAKMP 500
68 #define UDP_PORT_RIP    520
69 #define UDP_PORT_VINES  573
70
71
72 struct hash_struct {
73   guint16 proto;
74   void (*dissect)(const u_char *, int, frame_data *, proto_tree *);
75   struct hash_struct *next;
76 };
77
78 struct hash_struct *hash_table[256];
79
80 /*
81  * These routines are for UDP, will be generalized soon: RJS
82  *
83  * XXX - note that they should probably check the IP address as well as
84  * the port number, so that we don't mistakenly identify packets as, say,
85  * TFTP, merely because they have a source or destination port number
86  * equal to the port being used by a TFTP daemon on some machine other
87  * than the one they're going to or from.
88  */
89
90 struct hash_struct *udp_find_hash_ent(guint16 proto) {
91
92   int idx = proto % 256;
93   struct hash_struct *hash_ent = hash_table[idx];
94
95   while (hash_ent != NULL) {
96
97     if (hash_ent -> proto == proto)
98       return hash_ent;
99   
100     hash_ent = hash_ent -> next;
101
102   }
103
104   return NULL;
105
106 }
107
108 void udp_hash_add(guint16 proto,
109         void (*dissect)(const u_char *, int, frame_data *, proto_tree *)) {
110
111   int idx = proto % 256;   /* Simply take the remainder, hope for no collisions */
112   struct hash_struct *hash_ent = (struct hash_struct *)malloc(sizeof(struct hash_struct));
113   struct hash_struct *hash_ent2;
114   
115   hash_ent -> proto = proto;
116   hash_ent -> dissect = dissect;
117   hash_ent -> next = NULL;
118
119   if (hash_ent == NULL) {
120
121     fprintf(stderr, "Could not allocate space for hash structure in dissect_udp\n");
122     exit(1);
123   }
124
125   if (hash_table[idx]) {  /* Something, add on end */
126
127     hash_ent2 = hash_table[idx];
128
129     while (hash_ent2 -> next != NULL)
130       hash_ent2 = hash_ent2 -> next;
131
132     hash_ent2 -> next = hash_ent;     /* Bad in pathalogical cases */
133
134   }
135   else {
136
137     hash_table[idx] = hash_ent;
138
139   }
140
141 }
142
143 void init_dissect_udp(void) {
144
145   int i;
146
147   for (i = 0; i < 256; i++) {
148
149     hash_table[i] = NULL;
150
151   }
152
153   /* Now add the protocols we know about */
154
155   udp_hash_add(UDP_PORT_BOOTPS, dissect_bootp);
156   udp_hash_add(UDP_PORT_TFTP, dissect_tftp);
157
158 }
159
160 void
161 dissect_udp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
162   e_udphdr  uh;
163   guint16    uh_sport, uh_dport, uh_ulen, uh_sum;
164   struct hash_struct *dissect_routine = NULL;
165   proto_tree *udp_tree;
166   proto_item *ti;
167   guint      payload;
168
169   /* To do: Check for {cap len,pkt len} < struct len */
170   /* Avoids alignment problems on many architectures. */
171   memcpy(&uh, &pd[offset], sizeof(e_udphdr));
172   uh_sport = ntohs(uh.uh_sport);
173   uh_dport = ntohs(uh.uh_dport);
174   uh_ulen  = ntohs(uh.uh_ulen);
175   uh_sum   = ntohs(uh.uh_sum);
176   
177   payload = pi.payload - sizeof(e_udphdr);
178
179   if (check_col(fd, COL_PROTOCOL))
180     col_add_str(fd, COL_PROTOCOL, "UDP");
181   if (check_col(fd, COL_INFO))
182     col_add_fstr(fd, COL_INFO, "Source port: %s  Destination port: %s",
183             get_udp_port(uh_sport), get_udp_port(uh_dport));
184   if (check_col(fd, COL_RES_SRC_PORT))
185     col_add_str(fd, COL_RES_SRC_PORT, get_udp_port(uh_sport));
186   if (check_col(fd, COL_UNRES_SRC_PORT))
187     col_add_fstr(fd, COL_UNRES_SRC_PORT, "%u", uh_sport);
188   if (check_col(fd, COL_RES_DST_PORT))
189     col_add_str(fd, COL_RES_DST_PORT, get_udp_port(uh_dport));
190   if (check_col(fd, COL_UNRES_DST_PORT))
191     col_add_fstr(fd, COL_UNRES_DST_PORT, "%u", uh_dport);
192     
193   if (tree) {
194     ti = proto_tree_add_text(tree, offset, 8, "User Datagram Protocol");
195     udp_tree = proto_item_add_subtree(ti, ETT_UDP);
196     proto_tree_add_text(udp_tree, offset,     2, "Source port: %s (%u)",
197       get_udp_port(uh_sport), uh_sport);
198     proto_tree_add_text(udp_tree, offset + 2, 2, "Destination port: %s (%u)",
199       get_udp_port(uh_dport), uh_dport);
200     proto_tree_add_text(udp_tree, offset + 4, 2, "Length: %u", uh_ulen);
201     proto_tree_add_text(udp_tree, offset + 6, 2, "Checksum: 0x%04x", uh_sum);
202   }
203
204   /* Skip over header */
205   offset += 8;
206
207   /* XXX - we should do all of this through the table of ports. */
208 #define PORT_IS(port)   (uh_sport == port || uh_dport == port)
209  if (PORT_IS(UDP_PORT_BOOTPS))
210       dissect_bootp(pd, offset, fd, tree);
211  else if (PORT_IS(UDP_PORT_DNS))
212       dissect_dns(pd, offset, fd, tree);
213  else if (PORT_IS(UDP_PORT_ISAKMP))
214       dissect_isakmp(pd, offset, fd, tree);
215  else if (PORT_IS(UDP_PORT_RIP)) {
216       /* we should check the source port too (RIP: UDP src and dst port 520) */
217       dissect_rip(pd, offset, fd, tree);
218  } else if (PORT_IS(UDP_PORT_NBNS))
219       dissect_nbns(pd, offset, fd, tree);
220  else if (PORT_IS(UDP_PORT_NBDGM))
221       dissect_nbdgm(pd, offset, fd, tree, payload);
222  else if (PORT_IS(UDP_PORT_IPX)) /* RFC 1234 */
223       dissect_ipx(pd, offset, fd, tree);
224 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
225  else if (PORT_IS(UDP_PORT_SNMP))
226       dissect_snmp(pd, offset, fd, tree);
227 #endif
228  else if (PORT_IS(UDP_PORT_VINES)) {
229       /* FIXME: AFAIK, src and dst port must be the same */
230       dissect_vines_frp(pd, offset, fd, tree);
231  } else if (PORT_IS(UDP_PORT_TFTP)) {
232       /* This is the first point of call, but it adds a dynamic call */
233       udp_hash_add(MAX(uh_sport, uh_dport), dissect_tftp);  /* Add to table */
234       dissect_tftp(pd, offset, fd, tree);
235  } else {
236       /* OK, find a routine in the table, else use the default */
237
238       if ((dissect_routine = udp_find_hash_ent(uh_sport))) {
239
240         struct hash_struct *dr2 = udp_find_hash_ent(uh_dport);
241
242         if (dr2 == NULL) {  /* Not in the table, add */
243
244           udp_hash_add(uh_dport, dissect_tftp);
245
246         }
247
248         dissect_routine -> dissect(pd, offset, fd, tree);
249       }
250       else if ((dissect_routine = udp_find_hash_ent(uh_dport))) {
251
252         dissect_routine -> dissect(pd, offset, fd, tree);
253
254       }
255       else {
256
257         dissect_data(pd, offset, fd, tree);
258       }
259   }
260 }