Replace the ETT_ "enum" members, declared in "packet.h", with
[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.35 1999/11/16 11:43:01 guy 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 static int proto_udp = -1;              
48 static int hf_udp_srcport = -1;
49 static int hf_udp_dstport = -1;
50 static int hf_udp_port = -1;
51 static int hf_udp_length = -1;
52 static int hf_udp_checksum = -1;
53
54 static gint ett_udp = -1;
55
56 /* UDP structs and definitions */
57
58 typedef struct _e_udphdr {
59   guint16 uh_sport;
60   guint16 uh_dport;
61   guint16 uh_ulen;
62   guint16 uh_sum;
63 } e_udphdr;
64
65 /* UDP Ports -> should go in packet-udp.h */
66
67 #define UDP_PORT_DNS     53
68 #define UDP_PORT_BOOTPS  67
69 #define UDP_PORT_TFTP    69
70 #define UDP_PORT_IPX    213
71 #define UDP_PORT_NTP    123
72 #define UDP_PORT_NBNS   137
73 #define UDP_PORT_NBDGM  138
74 #define UDP_PORT_SNMP   161
75 #define UDP_PORT_ISAKMP 500
76 #define UDP_PORT_RIP    520
77 #define UDP_PORT_RIPNG  521
78 #define UDP_PORT_VINES  573
79 #define UDP_PORT_RADIUS 1645
80 #define UDP_PORT_RADIUS_NEW 1812
81 #define UDP_PORT_RADACCT 1646
82 #define UDP_PORT_RADACCT_NEW 1813
83 #define UDP_PORT_ICP    3130
84 #define UDP_PORT_ICQ    4000
85 #define UDP_PORT_RX_LOW 7000
86 #define UDP_PORT_RX_HIGH 7009
87 #define UDP_PORT_RX_AFS_BACKUPS 7021
88
89 struct hash_struct {
90   guint16 proto;
91   void (*dissect)(const u_char *, int, frame_data *, proto_tree *);
92   struct hash_struct *next;
93 };
94
95 static struct hash_struct *hash_table[256];
96
97 /*
98  * These routines are for UDP, will be generalized soon: RJS
99  *
100  * XXX - note that they should probably check the IP address as well as
101  * the port number, so that we don't mistakenly identify packets as, say,
102  * TFTP, merely because they have a source or destination port number
103  * equal to the port being used by a TFTP daemon on some machine other
104  * than the one they're going to or from.
105  */
106
107 struct hash_struct *udp_find_hash_ent(guint16 proto) {
108
109   int idx = proto % 256;
110   struct hash_struct *hash_ent = hash_table[idx];
111
112   while (hash_ent != NULL) {
113
114     if (hash_ent -> proto == proto)
115       return hash_ent;
116   
117     hash_ent = hash_ent -> next;
118
119   }
120
121   return NULL;
122
123 }
124
125 void udp_hash_add(guint16 proto,
126         void (*dissect)(const u_char *, int, frame_data *, proto_tree *)) {
127
128   int idx = proto % 256;   /* Simply take the remainder, hope for no collisions */
129   struct hash_struct *hash_ent = (struct hash_struct *)malloc(sizeof(struct hash_struct));
130   struct hash_struct *hash_ent2;
131   
132   hash_ent -> proto = proto;
133   hash_ent -> dissect = dissect;
134   hash_ent -> next = NULL;
135
136   if (hash_ent == NULL) {
137
138     fprintf(stderr, "Could not allocate space for hash structure in dissect_udp\n");
139     exit(1);
140   }
141
142   if (hash_table[idx]) {  /* Something, add on end */
143
144     hash_ent2 = hash_table[idx];
145
146     while (hash_ent2 -> next != NULL)
147       hash_ent2 = hash_ent2 -> next;
148
149     hash_ent2 -> next = hash_ent;     /* Bad in pathalogical cases */
150
151   }
152   else {
153
154     hash_table[idx] = hash_ent;
155
156   }
157
158 }
159
160 void init_dissect_udp(void) {
161
162   int i;
163
164   for (i = 0; i < 256; i++) {
165
166     hash_table[i] = NULL;
167
168   }
169
170   /* Now add the protocols we know about */
171
172   udp_hash_add(UDP_PORT_BOOTPS, dissect_bootp);
173   udp_hash_add(UDP_PORT_TFTP, dissect_tftp);
174
175 }
176
177 void
178 dissect_udp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
179   e_udphdr  uh;
180   guint16    uh_sport, uh_dport, uh_ulen, uh_sum;
181   struct hash_struct *dissect_routine = NULL;
182   proto_tree *udp_tree;
183   proto_item *ti;
184
185   if (!BYTES_ARE_IN_FRAME(offset, sizeof(e_udphdr))) {
186     dissect_data(pd, offset, fd, tree);
187     return;
188   }
189
190   /* Avoids alignment problems on many architectures. */
191   memcpy(&uh, &pd[offset], sizeof(e_udphdr));
192   uh_sport = ntohs(uh.uh_sport);
193   uh_dport = ntohs(uh.uh_dport);
194   uh_ulen  = ntohs(uh.uh_ulen);
195   uh_sum   = ntohs(uh.uh_sum);
196   
197   if (check_col(fd, COL_PROTOCOL))
198     col_add_str(fd, COL_PROTOCOL, "UDP");
199   if (check_col(fd, COL_INFO))
200     col_add_fstr(fd, COL_INFO, "Source port: %s  Destination port: %s",
201             get_udp_port(uh_sport), get_udp_port(uh_dport));
202     
203   if (tree) {
204     ti = proto_tree_add_item(tree, proto_udp, offset, 8);
205     udp_tree = proto_item_add_subtree(ti, ett_udp);
206
207     proto_tree_add_item_format(udp_tree, hf_udp_srcport, offset, 2, uh_sport,
208         "Source port: %s (%u)", get_udp_port(uh_sport), uh_sport);
209     proto_tree_add_item_format(udp_tree, hf_udp_dstport, offset + 2, 2, uh_dport,
210         "Destination port: %s (%u)", get_udp_port(uh_dport), uh_dport);
211
212     proto_tree_add_item_hidden(udp_tree, hf_udp_port, offset, 2, uh_sport);
213     proto_tree_add_item_hidden(udp_tree, hf_udp_port, offset+2, 2, uh_dport);
214
215     proto_tree_add_item(udp_tree, hf_udp_length, offset + 4, 2,  uh_ulen);
216     proto_tree_add_item_format(udp_tree, hf_udp_checksum, offset + 6, 2, uh_sum,
217         "Checksum: 0x%04x", uh_sum);
218   }
219
220   /* Skip over header */
221   offset += 8;
222
223   pi.ptype = PT_UDP;
224   pi.srcport = uh_sport;
225   pi.destport = uh_dport;
226
227   /* ONC RPC.  We can't base this on anything in the UDP header; we have
228      to look at the payload.  If "dissect_rpc()" returns TRUE, it was
229      an RPC packet, otherwise it's some other type of packet. */
230   if (dissect_rpc(pd, offset, fd, tree))
231     return;
232
233   /* XXX - we should do all of this through the table of ports. */
234 #define PORT_IS(port)   (uh_sport == port || uh_dport == port)
235   if (PORT_IS(UDP_PORT_BOOTPS))
236       dissect_bootp(pd, offset, fd, tree);
237   else if (PORT_IS(UDP_PORT_DNS))
238       dissect_dns(pd, offset, fd, tree);
239   else if (PORT_IS(UDP_PORT_ISAKMP))
240       dissect_isakmp(pd, offset, fd, tree);
241   else if (PORT_IS(UDP_PORT_RIP)) {
242       /* we should check the source port too (RIP: UDP src and dst port 520) */
243       dissect_rip(pd, offset, fd, tree);
244   } else if (PORT_IS(UDP_PORT_RIPNG))
245       dissect_ripng(pd, offset, fd, tree);
246   else if (PORT_IS(UDP_PORT_NBNS))
247       dissect_nbns(pd, offset, fd, tree);
248   else if (PORT_IS(UDP_PORT_NBDGM))
249       dissect_nbdgm(pd, offset, fd, tree);
250   else if (PORT_IS(UDP_PORT_NTP))
251       dissect_ntp(pd, offset, fd, tree);
252   else if (PORT_IS(UDP_PORT_IPX)) /* RFC 1234 */
253       dissect_ipx(pd, offset, fd, tree);
254   else if ((uh_sport >= UDP_PORT_RX_LOW && uh_sport <= UDP_PORT_RX_HIGH) ||
255         (uh_dport >= UDP_PORT_RX_LOW && uh_dport <= UDP_PORT_RX_HIGH) ||
256         PORT_IS(UDP_PORT_RX_AFS_BACKUPS)) 
257       dissect_rx(pd, offset, fd, tree); /* transarc AFS's RX protocol */
258 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
259   else if (PORT_IS(UDP_PORT_SNMP))
260       dissect_snmp(pd, offset, fd, tree);
261 #endif
262   else if (PORT_IS(UDP_PORT_VINES)) {
263       /* FIXME: AFAIK, src and dst port must be the same */
264       dissect_vines_frp(pd, offset, fd, tree);
265   } else if (PORT_IS(UDP_PORT_TFTP)) {
266       /* This is the first point of call, but it adds a dynamic call */
267       udp_hash_add(MAX(uh_sport, uh_dport), dissect_tftp);  /* Add to table */
268       dissect_tftp(pd, offset, fd, tree);
269   } else if (PORT_IS(UDP_PORT_RADIUS) ||
270                 PORT_IS(UDP_PORT_RADACCT) ||
271                 PORT_IS(UDP_PORT_RADIUS_NEW) ||
272                 PORT_IS(UDP_PORT_RADACCT_NEW) ) {
273       dissect_radius(pd, offset, fd, tree);
274   } else if ( PORT_IS(UDP_PORT_ICP)) {
275         dissect_icp(pd,offset,fd,tree);
276  } else if ( PORT_IS(UDP_PORT_ICQ)) {
277         dissect_icq(pd,offset,fd,tree);
278  } else {
279       /* OK, find a routine in the table, else use the default */
280
281       if ((dissect_routine = udp_find_hash_ent(uh_sport))) {
282
283         struct hash_struct *dr2 = udp_find_hash_ent(uh_dport);
284
285         if (dr2 == NULL) {  /* Not in the table, add */
286
287           udp_hash_add(uh_dport, dissect_tftp);
288
289         }
290
291         dissect_routine -> dissect(pd, offset, fd, tree);
292       }
293       else if ((dissect_routine = udp_find_hash_ent(uh_dport))) {
294
295         dissect_routine -> dissect(pd, offset, fd, tree);
296
297       }
298       else {
299
300         dissect_data(pd, offset, fd, tree);
301       }
302   }
303 }
304
305 void
306 proto_register_udp(void)
307 {
308         static hf_register_info hf[] = {
309                 { &hf_udp_srcport,
310                 { "Source Port",        "udp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
311                         "" }},
312
313                 { &hf_udp_dstport,
314                 { "Destination Port",   "udp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
315                         "" }},
316
317                 { &hf_udp_port,
318                 { "Source or Destination Port", "udp.port", FT_UINT16, BASE_DEC,  NULL, 0x0,
319                         "" }},
320
321                 { &hf_udp_length,
322                 { "Length",             "udp.length", FT_UINT16, BASE_DEC, NULL, 0x0,
323                         "" }},
324
325                 { &hf_udp_checksum,
326                 { "Checksum",           "udp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
327                         "" }},
328         };
329         static gint *ett[] = {
330                 &ett_udp,
331         };
332
333         proto_udp = proto_register_protocol("User Datagram Protocol", "udp");
334         proto_register_field_array(proto_udp, hf, array_length(hf));
335         proto_register_subtree_array(ett, array_length(ett));
336 }