/* packet-udp.c * Routines for UDP packet disassembly * * $Id: packet-udp.c,v 1.105 2002/08/28 21:00:36 jmayer Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * Richard Sharpe, 13-Feb-1999, added dispatch table support and * support for tftp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include "ipproto.h" #include "in_cksum.h" #include "prefs.h" #include "packet-udp.h" #include "packet-ip.h" #include static int proto_udp = -1; static int hf_udp_srcport = -1; static int hf_udp_dstport = -1; static int hf_udp_port = -1; static int hf_udp_length = -1; static int hf_udp_checksum = -1; static int hf_udp_checksum_bad = -1; static gint ett_udp = -1; /* Place UDP summary in proto tree */ static gboolean udp_summary_in_tree = TRUE; /* UDP structs and definitions */ typedef struct _e_udphdr { guint16 uh_sport; guint16 uh_dport; guint16 uh_ulen; guint16 uh_sum; } e_udphdr; static dissector_table_t udp_dissector_table; static heur_dissector_list_t heur_subdissector_list; static dissector_handle_t data_handle; /* Determine if there is a sub-dissector and call it. This has been */ /* separated into a stand alone routine to other protocol dissectors */ /* can call to it, ie. socks */ void decode_udp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int uh_sport, int uh_dport) { tvbuff_t *next_tvb; int low_port, high_port; next_tvb = tvb_new_subset(tvb, offset, -1, -1); /* determine if this packet is part of a conversation and call dissector */ /* for the conversation if available */ if (try_conversation_dissector(&pinfo->src, &pinfo->dst, PT_UDP, uh_sport, uh_dport, next_tvb, pinfo, tree)) return; /* Do lookups with the subdissector table. We try the port number with the lower value first, followed by the port number with the higher value. This means that, for packets where a dissector is registered for *both* port numbers: 1) we pick the same dissector for traffic going in both directions; 2) we prefer the port number that's more likely to be the right one (as that prefers well-known ports to reserved ports); although there is, of course, no guarantee that any such strategy will always pick the right port number. XXX - we ignore port numbers of 0, as some dissectors use a port number of 0 to disable the port, and as RFC 768 says that the source port in UDP datagrams is optional and is 0 if not used. */ if (uh_sport > uh_dport) { low_port = uh_dport; high_port = uh_sport; } else { low_port = uh_sport; high_port = uh_dport; } if (low_port != 0 && dissector_try_port(udp_dissector_table, low_port, next_tvb, pinfo, tree)) return; if (high_port != 0 && dissector_try_port(udp_dissector_table, high_port, next_tvb, pinfo, tree)) return; /* do lookup with the heuristic subdissector table */ if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree)) return; call_dissector(data_handle,next_tvb, pinfo, tree); } static void dissect_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { e_udphdr uh; guint16 uh_sport, uh_dport, uh_ulen, uh_sum; proto_tree *udp_tree; proto_item *ti; guint len; guint reported_len; vec_t cksum_vec[4]; guint32 phdr[2]; guint16 computed_cksum; int offset = 0; if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "UDP"); if (check_col(pinfo->cinfo, COL_INFO)) col_clear(pinfo->cinfo, COL_INFO); /* Avoids alignment problems on many architectures. */ tvb_memcpy(tvb, (guint8 *)&uh, offset, sizeof(e_udphdr)); uh_sport = g_ntohs(uh.uh_sport); uh_dport = g_ntohs(uh.uh_dport); uh_ulen = g_ntohs(uh.uh_ulen); uh_sum = g_ntohs(uh.uh_sum); if (check_col(pinfo->cinfo, COL_INFO)) col_add_fstr(pinfo->cinfo, COL_INFO, "Source port: %s Destination port: %s", get_udp_port(uh_sport), get_udp_port(uh_dport)); if (tree) { if (udp_summary_in_tree) { ti = proto_tree_add_protocol_format(tree, proto_udp, tvb, offset, 8, "User Datagram Protocol, Src Port: %s (%u), Dst Port: %s (%u)", get_udp_port(uh_sport), uh_sport, get_udp_port(uh_dport), uh_dport); } else { ti = proto_tree_add_item(tree, proto_udp, tvb, offset, 8, FALSE); } udp_tree = proto_item_add_subtree(ti, ett_udp); proto_tree_add_uint_format(udp_tree, hf_udp_srcport, tvb, offset, 2, uh_sport, "Source port: %s (%u)", get_udp_port(uh_sport), uh_sport); proto_tree_add_uint_format(udp_tree, hf_udp_dstport, tvb, offset + 2, 2, uh_dport, "Destination port: %s (%u)", get_udp_port(uh_dport), uh_dport); proto_tree_add_uint_hidden(udp_tree, hf_udp_port, tvb, offset, 2, uh_sport); proto_tree_add_uint_hidden(udp_tree, hf_udp_port, tvb, offset+2, 2, uh_dport); proto_tree_add_uint(udp_tree, hf_udp_length, tvb, offset + 4, 2, uh_ulen); reported_len = tvb_reported_length(tvb); len = tvb_length(tvb); if (uh_sum == 0) { /* No checksum supplied in the packet. */ proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, uh_sum, "Checksum: 0x%04x (none)", uh_sum); } else if (!pinfo->fragmented && len >= reported_len && len >= uh_ulen) { /* The packet isn't part of a fragmented datagram and isn't truncated, so we can checksum it. XXX - make a bigger scatter-gather list once we do fragment reassembly? */ /* Set up the fields of the pseudo-header. */ cksum_vec[0].ptr = pinfo->src.data; cksum_vec[0].len = pinfo->src.len; cksum_vec[1].ptr = pinfo->dst.data; cksum_vec[1].len = pinfo->dst.len; cksum_vec[2].ptr = (const guint8 *)&phdr; switch (pinfo->src.type) { case AT_IPv4: phdr[0] = g_htonl((IP_PROTO_UDP<<16) + reported_len); cksum_vec[2].len = 4; break; case AT_IPv6: phdr[0] = g_htonl(reported_len); phdr[1] = g_htonl(IP_PROTO_UDP); cksum_vec[2].len = 8; break; default: /* TCP runs only atop IPv4 and IPv6.... */ g_assert_not_reached(); break; } cksum_vec[3].ptr = tvb_get_ptr(tvb, offset, len); cksum_vec[3].len = reported_len; computed_cksum = in_cksum(&cksum_vec[0], 4); if (computed_cksum == 0) { proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, uh_sum, "Checksum: 0x%04x (correct)", uh_sum); } else { proto_tree_add_boolean_hidden(udp_tree, hf_udp_checksum_bad, tvb, offset + 6, 2, TRUE); proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, uh_sum, "Checksum: 0x%04x (incorrect, should be 0x%04x)", uh_sum, in_cksum_shouldbe(uh_sum, computed_cksum)); } } else { proto_tree_add_uint_format(udp_tree, hf_udp_checksum, tvb, offset + 6, 2, uh_sum, "Checksum: 0x%04x", uh_sum); } } /* Skip over header */ offset += 8; pinfo->ptype = PT_UDP; pinfo->srcport = uh_sport; pinfo->destport = uh_dport; /* call sub-dissectors */ decode_udp_ports( tvb, offset, pinfo, tree, uh_sport, uh_dport); } void proto_register_udp(void) { module_t *udp_module; static hf_register_info hf[] = { { &hf_udp_srcport, { "Source Port", "udp.srcport", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_udp_dstport, { "Destination Port", "udp.dstport", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_udp_port, { "Source or Destination Port", "udp.port", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_udp_length, { "Length", "udp.length", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }}, { &hf_udp_checksum_bad, { "Bad Checksum", "udp.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }}, { &hf_udp_checksum, { "Checksum", "udp.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }}, }; static gint *ett[] = { &ett_udp, }; proto_udp = proto_register_protocol("User Datagram Protocol", "UDP", "udp"); proto_register_field_array(proto_udp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); /* subdissector code */ udp_dissector_table = register_dissector_table("udp.port", "UDP port", FT_UINT16, BASE_DEC); register_heur_dissector_list("udp", &heur_subdissector_list); /* Register configuration preferences */ udp_module = prefs_register_protocol(proto_udp, NULL); prefs_register_bool_preference(udp_module, "udp_summary_in_tree", "Show UDP summary in protocol tree", "Whether the UDP summary line should be shown in the protocol tree", &udp_summary_in_tree); } void proto_reg_handoff_udp(void) { dissector_handle_t udp_handle; udp_handle = create_dissector_handle(dissect_udp, proto_udp); dissector_add("ip.proto", IP_PROTO_UDP, udp_handle); data_handle = find_dissector("data"); }