"uint" is defined on all platforms; use "guint" instead.
[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.103 2002/06/08 21:54:51 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
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 #include <string.h>
43
44 #include <glib.h>
45 #include <epan/packet.h>
46 #include <epan/resolv.h>
47 #include "ipproto.h"
48 #include "in_cksum.h"
49 #include "prefs.h"
50
51 #include "packet-udp.h"
52
53 #include "packet-ip.h"
54 #include <epan/conversation.h>
55
56 static int proto_udp = -1;              
57 static int hf_udp_srcport = -1;
58 static int hf_udp_dstport = -1;
59 static int hf_udp_port = -1;
60 static int hf_udp_length = -1;
61 static int hf_udp_checksum = -1;
62 static int hf_udp_checksum_bad = -1;
63
64 static gint ett_udp = -1;
65
66 /* Place UDP summary in proto tree */
67 static gboolean udp_summary_in_tree = TRUE;
68
69 /* UDP structs and definitions */
70
71 typedef struct _e_udphdr {
72   guint16 uh_sport;
73   guint16 uh_dport;
74   guint16 uh_ulen;
75   guint16 uh_sum;
76 } e_udphdr;
77
78 static dissector_table_t udp_dissector_table;
79 static heur_dissector_list_t heur_subdissector_list;
80 static dissector_handle_t data_handle;
81
82 /* Determine if there is a sub-dissector and call it.  This has been */
83 /* separated into a stand alone routine to other protocol dissectors */
84 /* can call to it, ie. socks    */
85
86 void
87 decode_udp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo,
88         proto_tree *tree, int uh_sport, int uh_dport)
89 {
90   tvbuff_t *next_tvb;
91   int low_port, high_port;
92
93   next_tvb = tvb_new_subset(tvb, offset, -1, -1);
94
95 /* determine if this packet is part of a conversation and call dissector */
96 /* for the conversation if available */
97
98   if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_UDP,
99                 uh_sport, uh_dport, next_tvb, pinfo, tree))
100     return;
101
102   /* Do lookups with the subdissector table.
103      We try the port number with the lower value first, followed by the
104      port number with the higher value.  This means that, for packets
105      where a dissector is registered for *both* port numbers:
106
107         1) we pick the same dissector for traffic going in both directions;
108
109         2) we prefer the port number that's more likely to be the right
110            one (as that prefers well-known ports to reserved ports);
111
112      although there is, of course, no guarantee that any such strategy
113      will always pick the right port number.
114
115      XXX - we ignore port numbers of 0, as some dissectors use a port
116      number of 0 to disable the port, and as RFC 768 says that the source
117      port in UDP datagrams is optional and is 0 if not used. */
118   if (uh_sport > uh_dport) {
119     low_port = uh_dport;
120     high_port = uh_sport;
121   } else {
122     low_port = uh_sport;
123     high_port = uh_dport;
124   }
125   if (low_port != 0 &&
126       dissector_try_port(udp_dissector_table, low_port, next_tvb, pinfo, tree))
127     return;
128   if (high_port != 0 &&
129       dissector_try_port(udp_dissector_table, high_port, next_tvb, pinfo, tree))
130     return;
131
132   /* do lookup with the heuristic subdissector table */
133   if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree))
134     return;
135
136   call_dissector(data_handle,next_tvb, pinfo, tree);
137 }
138
139
140 static void
141 dissect_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
142 {
143   e_udphdr  uh;
144   guint16    uh_sport, uh_dport, uh_ulen, uh_sum;
145   proto_tree *udp_tree;
146   proto_item *ti;
147   guint      len;
148   guint      reported_len;
149   vec_t      cksum_vec[4];
150   guint32    phdr[2];
151   guint16    computed_cksum;
152   int        offset = 0;
153
154   if (check_col(pinfo->cinfo, COL_PROTOCOL))
155     col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDP");
156   if (check_col(pinfo->cinfo, COL_INFO))
157     col_clear(pinfo->cinfo, COL_INFO);
158
159   /* Avoids alignment problems on many architectures. */
160   tvb_memcpy(tvb, (guint8 *)&uh, offset, sizeof(e_udphdr));
161   uh_sport = ntohs(uh.uh_sport);
162   uh_dport = ntohs(uh.uh_dport);
163   uh_ulen  = ntohs(uh.uh_ulen);
164   uh_sum   = ntohs(uh.uh_sum);
165   
166   if (check_col(pinfo->cinfo, COL_INFO))
167     col_add_fstr(pinfo->cinfo, COL_INFO, "Source port: %s  Destination port: %s",
168             get_udp_port(uh_sport), get_udp_port(uh_dport));
169     
170   if (tree) {
171     if (udp_summary_in_tree) {
172       ti = proto_tree_add_protocol_format(tree, proto_udp, tvb, offset, 8,
173       "User Datagram Protocol, Src Port: %s (%u), Dst Port: %s (%u)",
174       get_udp_port(uh_sport), uh_sport, get_udp_port(uh_dport), uh_dport);
175     } else {
176       ti = proto_tree_add_item(tree, proto_udp, tvb, offset, 8, FALSE);
177     }
178     udp_tree = proto_item_add_subtree(ti, ett_udp);
179
180     proto_tree_add_uint_format(udp_tree, hf_udp_srcport, tvb, offset, 2, uh_sport,
181         "Source port: %s (%u)", get_udp_port(uh_sport), uh_sport);
182     proto_tree_add_uint_format(udp_tree, hf_udp_dstport, tvb, offset + 2, 2, uh_dport,
183         "Destination port: %s (%u)", get_udp_port(uh_dport), uh_dport);
184
185     proto_tree_add_uint_hidden(udp_tree, hf_udp_port, tvb, offset, 2, uh_sport);
186     proto_tree_add_uint_hidden(udp_tree, hf_udp_port, tvb, offset+2, 2, uh_dport);
187
188     proto_tree_add_uint(udp_tree, hf_udp_length, tvb, offset + 4, 2,  uh_ulen);
189     reported_len = tvb_reported_length(tvb);
190     len = tvb_length(tvb);
191     if (uh_sum == 0) {
192       /* No checksum supplied in the packet. */
193       proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb,
194         offset + 6, 2, uh_sum, "Checksum: 0x%04x (none)", uh_sum);
195     } else if (!pinfo->fragmented && len >= reported_len && len >= uh_ulen) {
196       /* The packet isn't part of a fragmented datagram and isn't
197          truncated, so we can checksum it.
198          XXX - make a bigger scatter-gather list once we do fragment
199          reassembly? */
200
201       /* Set up the fields of the pseudo-header. */
202       cksum_vec[0].ptr = pinfo->src.data;
203       cksum_vec[0].len = pinfo->src.len;
204       cksum_vec[1].ptr = pinfo->dst.data;
205       cksum_vec[1].len = pinfo->dst.len;
206       cksum_vec[2].ptr = (const guint8 *)&phdr;
207       switch (pinfo->src.type) {
208
209       case AT_IPv4:
210         phdr[0] = htonl((IP_PROTO_UDP<<16) + reported_len);
211         cksum_vec[2].len = 4;
212         break;
213
214       case AT_IPv6:
215         phdr[0] = htonl(reported_len);
216         phdr[1] = htonl(IP_PROTO_UDP);
217         cksum_vec[2].len = 8;
218         break;
219
220       default:
221         /* TCP runs only atop IPv4 and IPv6.... */
222         g_assert_not_reached();
223         break;
224       }
225       cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, len);
226       cksum_vec[3].len = reported_len;
227       computed_cksum = in_cksum(&cksum_vec[0], 4);
228       if (computed_cksum == 0) {
229         proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb,
230           offset + 6, 2, uh_sum, "Checksum: 0x%04x (correct)", uh_sum);
231       } else {
232         proto_tree_add_boolean_hidden(udp_tree, hf_udp_checksum_bad, tvb,
233            offset + 6, 2, TRUE);
234         proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb,
235           offset + 6, 2, uh_sum,
236           "Checksum: 0x%04x (incorrect, should be 0x%04x)", uh_sum,
237            in_cksum_shouldbe(uh_sum, computed_cksum));
238       }
239     } else {
240       proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb,
241         offset + 6, 2, uh_sum, "Checksum: 0x%04x", uh_sum);
242     }
243   }
244
245   /* Skip over header */
246   offset += 8;
247
248   pinfo->ptype = PT_UDP;
249   pinfo->srcport = uh_sport;
250   pinfo->destport = uh_dport;
251
252 /* call sub-dissectors */
253   decode_udp_ports( tvb, offset, pinfo, tree, uh_sport, uh_dport);
254
255 }
256
257 void
258 proto_register_udp(void)
259 {
260         module_t *udp_module;
261         static hf_register_info hf[] = {
262                 { &hf_udp_srcport,
263                 { "Source Port",        "udp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0,
264                         "", HFILL }},
265
266                 { &hf_udp_dstport,
267                 { "Destination Port",   "udp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0,
268                         "", HFILL }},
269
270                 { &hf_udp_port,
271                 { "Source or Destination Port", "udp.port", FT_UINT16, BASE_DEC,  NULL, 0x0,
272                         "", HFILL }},
273
274                 { &hf_udp_length,
275                 { "Length",             "udp.length", FT_UINT16, BASE_DEC, NULL, 0x0,
276                         "", HFILL }},
277
278                 { &hf_udp_checksum_bad,
279                 { "Bad Checksum",       "udp.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
280                         "", HFILL }},
281
282                 { &hf_udp_checksum,
283                 { "Checksum",           "udp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0,
284                         "", HFILL }},
285         };
286         static gint *ett[] = {
287                 &ett_udp,
288         };
289
290         proto_udp = proto_register_protocol("User Datagram Protocol",
291             "UDP", "udp");
292         proto_register_field_array(proto_udp, hf, array_length(hf));
293         proto_register_subtree_array(ett, array_length(ett));
294
295 /* subdissector code */
296         udp_dissector_table = register_dissector_table("udp.port",
297             "UDP port", FT_UINT16, BASE_DEC);
298         register_heur_dissector_list("udp", &heur_subdissector_list);
299         
300         /* Register configuration preferences */
301         udp_module = prefs_register_protocol(proto_udp, NULL);
302         prefs_register_bool_preference(udp_module, "udp_summary_in_tree",
303         "Show UDP summary in protocol tree", 
304         "Whether the UDP summary line should be shown in the protocol tree",
305         &udp_summary_in_tree);
306 }
307
308 void
309 proto_reg_handoff_udp(void)
310 {
311         dissector_handle_t udp_handle;
312
313         udp_handle = create_dissector_handle(dissect_udp, proto_udp);
314         dissector_add("ip.proto", IP_PROTO_UDP, udp_handle);
315         data_handle = find_dissector("data");
316 }