aboutsummaryrefslogtreecommitdiffstats
path: root/packet-ip.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2003-01-14 18:54:29 +0000
committerGuy Harris <guy@alum.mit.edu>2003-01-14 18:54:29 +0000
commit1372d1c5e03cdeeff67cc2d947766746a4bea9bc (patch)
treee3ec61a70c60e526935a12eba82b68913b8f396f /packet-ip.c
parenta476a8b4c34542d8ddd39cf81e6b648bfb8bed89 (diff)
Don't copy the entire IP header into a structure, extract stuff from it
as you dissect it, so we can dissect packets that are cut short before the end of an IP header. Check for an IP total length less than the header length. svn path=/trunk/; revision=6921
Diffstat (limited to 'packet-ip.c')
-rw-r--r--packet-ip.c244
1 files changed, 140 insertions, 104 deletions
diff --git a/packet-ip.c b/packet-ip.c
index cca5738e8a..51cc36dc8a 100644
--- a/packet-ip.c
+++ b/packet-ip.c
@@ -1,7 +1,7 @@
/* packet-ip.c
* Routines for IP and miscellaneous IP protocol packet disassembly
*
- * $Id: packet-ip.c,v 1.177 2002/12/19 11:22:27 sahlberg Exp $
+ * $Id: packet-ip.c,v 1.178 2003/01/14 18:54:29 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -194,20 +194,6 @@ static gint ett_icmp_mip_flags = -1;
/* IP structs and definitions */
-typedef struct _e_ip
- {
- guint8 ip_v_hl; /* combines ip_v and ip_hl */
- guint8 ip_tos;
- guint16 ip_len;
- guint16 ip_id;
- guint16 ip_off;
- guint8 ip_ttl;
- guint8 ip_p;
- guint16 ip_sum;
- guint32 ip_src;
- guint32 ip_dst;
- } e_ip;
-
/* Offsets of fields within an IP header. */
#define IPH_V_HL 0
#define IPH_TOS 1
@@ -822,11 +808,19 @@ static guint16 ip_checksum(const guint8 *ptr, int len)
static void
dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- e_ip iph;
+ guint8 ip_v_hl; /* combines ip_v and ip_hl */
+ guint8 ip_tos;
+ guint16 ip_len;
+ guint16 ip_id;
+ guint16 ip_off;
+ guint8 ip_p;
+ guint16 ip_sum;
+ guint32 ip_src;
+ guint32 ip_dst;
proto_tree *ip_tree = NULL, *field_tree;
- proto_item *ti, *tf;
+ proto_item *ti = NULL, *tf;
int offset = 0;
- guint hlen, optlen, len;
+ guint hlen, optlen;
guint16 flags;
guint8 nxt;
guint16 ipsum;
@@ -840,36 +834,15 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (check_col(pinfo->cinfo, COL_INFO))
col_clear(pinfo->cinfo, COL_INFO);
- /* Avoids alignment problems on many architectures. */
- tvb_memcpy(tvb, (guint8 *)&iph, offset, sizeof(e_ip));
- iph.ip_len = g_ntohs(iph.ip_len);
- iph.ip_id = g_ntohs(iph.ip_id);
- iph.ip_off = g_ntohs(iph.ip_off);
- iph.ip_sum = g_ntohs(iph.ip_sum);
-
- /* Length of IP datagram.
- XXX - what if this is greater than the reported length of the
- tvbuff? This could happen, for example, in an IP datagram
- inside an ICMP datagram; we need to somehow let the
- dissector we call know that, as it might want to avoid
- doing its checksumming. */
- len = iph.ip_len;
-
- /* Adjust the length of this tvbuff to include only the IP datagram. */
- set_actual_length(tvb, len);
-
- hlen = lo_nibble(iph.ip_v_hl) * 4; /* IP header length, in bytes */
+ ip_v_hl = tvb_get_guint8(tvb, offset);
+ hlen = lo_nibble(ip_v_hl) * 4; /* IP header length, in bytes */
if (tree) {
- if (ip_summary_in_tree && hlen >= IPH_MIN_LEN) {
- ti = proto_tree_add_protocol_format(tree, proto_ip, tvb, offset, hlen,
- "Internet Protocol, Src Addr: %s (%s), Dst Addr: %s (%s)",
- get_hostname(iph.ip_src), ip_to_str((guint8 *) &iph.ip_src),
- get_hostname(iph.ip_dst), ip_to_str((guint8 *) &iph.ip_dst));
- } else {
- ti = proto_tree_add_item(tree, proto_ip, tvb, offset, hlen, FALSE);
- }
+ ti = proto_tree_add_item(tree, proto_ip, tvb, offset, hlen, FALSE);
ip_tree = proto_item_add_subtree(ti, ett_ip);
+
+ proto_tree_add_uint(ip_tree, hf_ip_version, tvb, offset, 1,
+ hi_nibble(ip_v_hl));
}
if (hlen < IPH_MIN_LEN) {
@@ -878,82 +851,145 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
hlen, IPH_MIN_LEN);
if (tree) {
proto_tree_add_uint_format(ip_tree, hf_ip_hdr_len, tvb, offset, 1, hlen,
- "Header length: %u bytes (bogus, must be at least %u)", hlen,
- IPH_MIN_LEN);
+ "Header length: %u bytes (bogus, must be at least %u)", hlen,
+ IPH_MIN_LEN);
}
return;
}
- /*
- * Compute the checksum of the IP header.
- */
- ipsum = ip_checksum(tvb_get_ptr(tvb, offset, hlen), hlen);
-
if (tree) {
- proto_tree_add_uint(ip_tree, hf_ip_version, tvb, offset, 1, hi_nibble(iph.ip_v_hl));
proto_tree_add_uint_format(ip_tree, hf_ip_hdr_len, tvb, offset, 1, hlen,
"Header length: %u bytes", hlen);
+ }
+ ip_tos = tvb_get_guint8(tvb, offset + 1);
+ if (tree) {
if (g_ip_dscp_actif) {
- tf = proto_tree_add_uint_format(ip_tree, hf_ip_dsfield, tvb, offset + 1, 1, iph.ip_tos,
- "Differentiated Services Field: 0x%02x (DSCP 0x%02x: %s; ECN: 0x%02x)", iph.ip_tos,
- IPDSFIELD_DSCP(iph.ip_tos), val_to_str(IPDSFIELD_DSCP(iph.ip_tos), dscp_vals,
- "Unknown DSCP"),IPDSFIELD_ECN(iph.ip_tos));
+ tf = proto_tree_add_uint_format(ip_tree, hf_ip_dsfield, tvb, offset + 1, 1, ip_tos,
+ "Differentiated Services Field: 0x%02x (DSCP 0x%02x: %s; ECN: 0x%02x)", ip_tos,
+ IPDSFIELD_DSCP(ip_tos), val_to_str(IPDSFIELD_DSCP(ip_tos), dscp_vals,
+ "Unknown DSCP"),IPDSFIELD_ECN(ip_tos));
field_tree = proto_item_add_subtree(tf, ett_ip_dsfield);
- proto_tree_add_uint(field_tree, hf_ip_dsfield_dscp, tvb, offset + 1, 1, iph.ip_tos);
- proto_tree_add_uint(field_tree, hf_ip_dsfield_ect, tvb, offset + 1, 1, iph.ip_tos);
- proto_tree_add_uint(field_tree, hf_ip_dsfield_ce, tvb, offset + 1, 1, iph.ip_tos);
+ proto_tree_add_uint(field_tree, hf_ip_dsfield_dscp, tvb, offset + 1, 1, ip_tos);
+ proto_tree_add_uint(field_tree, hf_ip_dsfield_ect, tvb, offset + 1, 1, ip_tos);
+ proto_tree_add_uint(field_tree, hf_ip_dsfield_ce, tvb, offset + 1, 1, ip_tos);
} else {
- tf = proto_tree_add_uint_format(ip_tree, hf_ip_tos, tvb, offset + 1, 1, iph.ip_tos,
- "Type of service: 0x%02x (%s)", iph.ip_tos,
- val_to_str( IPTOS_TOS(iph.ip_tos), iptos_vals, "Unknown") );
+ tf = proto_tree_add_uint_format(ip_tree, hf_ip_tos, tvb, offset + 1, 1, ip_tos,
+ "Type of service: 0x%02x (%s)", ip_tos,
+ val_to_str( IPTOS_TOS(ip_tos), iptos_vals, "Unknown") );
field_tree = proto_item_add_subtree(tf, ett_ip_tos);
- proto_tree_add_uint(field_tree, hf_ip_tos_precedence, tvb, offset + 1, 1, iph.ip_tos);
- proto_tree_add_boolean(field_tree, hf_ip_tos_delay, tvb, offset + 1, 1, iph.ip_tos);
- proto_tree_add_boolean(field_tree, hf_ip_tos_throughput, tvb, offset + 1, 1, iph.ip_tos);
- proto_tree_add_boolean(field_tree, hf_ip_tos_reliability, tvb, offset + 1, 1, iph.ip_tos);
- proto_tree_add_boolean(field_tree, hf_ip_tos_cost, tvb, offset + 1, 1, iph.ip_tos);
+ proto_tree_add_uint(field_tree, hf_ip_tos_precedence, tvb, offset + 1, 1, ip_tos);
+ proto_tree_add_boolean(field_tree, hf_ip_tos_delay, tvb, offset + 1, 1, ip_tos);
+ proto_tree_add_boolean(field_tree, hf_ip_tos_throughput, tvb, offset + 1, 1, ip_tos);
+ proto_tree_add_boolean(field_tree, hf_ip_tos_reliability, tvb, offset + 1, 1, ip_tos);
+ proto_tree_add_boolean(field_tree, hf_ip_tos_cost, tvb, offset + 1, 1, ip_tos);
+ }
+ }
+
+ /* Length of IP datagram.
+ XXX - what if this is greater than the reported length of the
+ tvbuff? This could happen, for example, in an IP datagram
+ inside an ICMP datagram; we need to somehow let the
+ dissector we call know that, as it might want to avoid
+ doing its checksumming. */
+ ip_len = tvb_get_ntohs(tvb, offset + 2);
+
+ /* Adjust the length of this tvbuff to include only the IP datagram. */
+ set_actual_length(tvb, ip_len);
+
+ if (ip_len < hlen) {
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Bogus IP length (%u, less than header length %u)",
+ ip_len, hlen);
+ if (tree) {
+ proto_tree_add_uint_format(ip_tree, hf_ip_len, tvb, offset + 2, 2, ip_len,
+ "Total length: %u bytes (bogus, less than header length %u)", ip_len,
+ hlen);
}
- proto_tree_add_uint(ip_tree, hf_ip_len, tvb, offset + 2, 2, iph.ip_len);
- proto_tree_add_uint(ip_tree, hf_ip_id, tvb, offset + 4, 2, iph.ip_id);
+ return;
+ }
+ if (tree)
+ proto_tree_add_uint(ip_tree, hf_ip_len, tvb, offset + 2, 2, ip_len);
- flags = (iph.ip_off & (IP_DF|IP_MF)) >> 12;
- tf = proto_tree_add_uint(ip_tree, hf_ip_flags, tvb, offset + 6, 1, flags);
+ ip_id = tvb_get_ntohs(tvb, offset + 4);
+ if (tree)
+ proto_tree_add_uint(ip_tree, hf_ip_id, tvb, offset + 4, 2, ip_id);
+
+ ip_off = tvb_get_ntohs(tvb, offset + 6);
+ if (tree) {
+ flags = (ip_off & (IP_DF|IP_MF)) >> 12;
+ tf = proto_tree_add_uint(ip_tree, hf_ip_flags, tvb, offset + 6, 1, flags);
field_tree = proto_item_add_subtree(tf, ett_ip_off);
proto_tree_add_boolean(field_tree, hf_ip_flags_df, tvb, offset + 6, 1, flags),
proto_tree_add_boolean(field_tree, hf_ip_flags_mf, tvb, offset + 6, 1, flags),
- proto_tree_add_uint(ip_tree, hf_ip_frag_offset, tvb, offset + 6, 2,
- (iph.ip_off & IP_OFFSET)*8);
+ proto_tree_add_uint(ip_tree, hf_ip_frag_offset, tvb, offset + 6, 2,
+ (ip_off & IP_OFFSET)*8);
+ }
- proto_tree_add_uint(ip_tree, hf_ip_ttl, tvb, offset + 8, 1, iph.ip_ttl);
- proto_tree_add_uint_format(ip_tree, hf_ip_proto, tvb, offset + 9, 1, iph.ip_p,
- "Protocol: %s (0x%02x)", ipprotostr(iph.ip_p), iph.ip_p);
+ if (tree)
+ proto_tree_add_item(ip_tree, hf_ip_ttl, tvb, offset + 8, 1, FALSE);
- if (ipsum == 0) {
- proto_tree_add_uint_format(ip_tree, hf_ip_checksum, tvb, offset + 10, 2, iph.ip_sum,
- "Header checksum: 0x%04x (correct)", iph.ip_sum);
- }
- else {
+ ip_p = tvb_get_guint8(tvb, offset + 9);
+ if (tree) {
+ proto_tree_add_uint_format(ip_tree, hf_ip_proto, tvb, offset + 9, 1, ip_p,
+ "Protocol: %s (0x%02x)", ipprotostr(ip_p), ip_p);
+ }
+
+ ip_sum = tvb_get_ntohs(tvb, offset + 10);
+
+ /*
+ * If we have the entire IP header available, check the checksum.
+ */
+ if (tvb_bytes_exist(tvb, offset, hlen)) {
+ ipsum = ip_checksum(tvb_get_ptr(tvb, offset, hlen), hlen);
+ if (tree) {
+ if (ipsum == 0) {
+ proto_tree_add_uint_format(ip_tree, hf_ip_checksum, tvb, offset + 10, 2, ip_sum,
+ "Header checksum: 0x%04x (correct)", ip_sum);
+ }
+ else {
proto_tree_add_boolean_hidden(ip_tree, hf_ip_checksum_bad, tvb, offset + 10, 2, TRUE);
- proto_tree_add_uint_format(ip_tree, hf_ip_checksum, tvb, offset + 10, 2, iph.ip_sum,
- "Header checksum: 0x%04x (incorrect, should be 0x%04x)", iph.ip_sum,
- in_cksum_shouldbe(iph.ip_sum, ipsum));
+ proto_tree_add_uint_format(ip_tree, hf_ip_checksum, tvb, offset + 10, 2, ip_sum,
+ "Header checksum: 0x%04x (incorrect, should be 0x%04x)", ip_sum,
+ in_cksum_shouldbe(ip_sum, ipsum));
+ }
+ }
+ } else {
+ ipsum = 0;
+ if (tree)
+ proto_tree_add_uint(ip_tree, hf_ip_checksum, tvb, offset + 10, 2, ip_sum);
+ }
+
+ tvb_memcpy(tvb, (guint8 *)&ip_src, offset + 12, 4);
+ if (tree) {
+ if (ip_summary_in_tree) {
+ proto_item_append_text(ti, ", Src Addr: %s (%s)",
+ get_hostname(ip_src), ip_to_str((guint8 *) &ip_src));
}
+ proto_tree_add_ipv4(ip_tree, hf_ip_src, tvb, offset + 12, 4, ip_src);
+ proto_tree_add_ipv4_hidden(ip_tree, hf_ip_addr, tvb, offset + 12, 4, ip_src);
+ }
- proto_tree_add_ipv4(ip_tree, hf_ip_src, tvb, offset + 12, 4, iph.ip_src);
- proto_tree_add_ipv4(ip_tree, hf_ip_dst, tvb, offset + 16, 4, iph.ip_dst);
- proto_tree_add_ipv4_hidden(ip_tree, hf_ip_addr, tvb, offset + 12, 4, iph.ip_src);
- proto_tree_add_ipv4_hidden(ip_tree, hf_ip_addr, tvb, offset + 16, 4, iph.ip_dst);
+ tvb_memcpy(tvb, (guint8 *)&ip_dst, offset + 16, 4);
+ if (tree) {
+ if (ip_summary_in_tree) {
+ proto_item_append_text(ti, ", Dst Addr: %s (%s)",
+ get_hostname(ip_dst), ip_to_str((guint8 *) &ip_dst));
+ }
+ proto_tree_add_ipv4(ip_tree, hf_ip_dst, tvb, offset + 16, 4, ip_dst);
+ proto_tree_add_ipv4_hidden(ip_tree, hf_ip_addr, tvb, offset + 16, 4, ip_dst);
+ }
+ if (tree) {
/* Decode IP options, if any. */
- if (hlen > sizeof (e_ip)) {
+ if (hlen > IPH_MIN_LEN) {
/* There's more than just the fixed-length header. Decode the
options. */
- optlen = hlen - sizeof (e_ip); /* length of options, in bytes */
- tf = proto_tree_add_text(ip_tree, tvb, offset + 20, optlen,
+ optlen = hlen - IPH_MIN_LEN; /* length of options, in bytes */
+ tf = proto_tree_add_text(ip_tree, tvb, offset + 20, optlen,
"Options: (%u bytes)", optlen);
field_tree = proto_item_add_subtree(tf, ett_ip_options);
dissect_ip_tcp_options(tvb, offset + 20, optlen,
@@ -961,11 +997,11 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
}
- pinfo->ipproto = iph.ip_p;
+ pinfo->ipproto = ip_p;
- pinfo->iplen = iph.ip_len;
+ pinfo->iplen = ip_len;
- pinfo->iphdrlen = lo_nibble(iph.ip_v_hl);
+ pinfo->iphdrlen = lo_nibble(ip_v_hl);
SET_ADDRESS(&pinfo->net_src, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_SRC, 4));
SET_ADDRESS(&pinfo->src, AT_IPv4, 4, tvb_get_ptr(tvb, offset + IPH_SRC, 4));
@@ -974,20 +1010,20 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* Skip over header + options */
offset += hlen;
- nxt = iph.ip_p; /* XXX - what if this isn't the same for all fragments? */
+ nxt = ip_p; /* XXX - what if this isn't the same for all fragments? */
/* If ip_defragment is on, this is a fragment, we have all the data
* in the fragment, and the header checksum is valid, then just add
* the fragment to the hashtable.
*/
save_fragmented = pinfo->fragmented;
- if (ip_defragment && (iph.ip_off & (IP_MF|IP_OFFSET)) &&
+ if (ip_defragment && (ip_off & (IP_MF|IP_OFFSET)) &&
tvb_reported_length(tvb) <= tvb_length(tvb) && ipsum == 0) {
- ipfd_head = fragment_add(tvb, offset, pinfo, iph.ip_id,
+ ipfd_head = fragment_add(tvb, offset, pinfo, ip_id,
ip_fragment_table,
- (iph.ip_off & IP_OFFSET)*8,
+ (ip_off & IP_OFFSET)*8,
pinfo->iplen - (pinfo->iphdrlen*4),
- iph.ip_off & IP_MF);
+ ip_off & IP_MF);
if (ipfd_head != NULL) {
/* OK, we have the complete reassembled payload.
@@ -1016,7 +1052,7 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
XXX - if we eventually don't save the reassembled contents of all
fragmented datagrams, we may want to always reassemble. */
- if (iph.ip_off & IP_OFFSET) {
+ if (ip_off & IP_OFFSET) {
/* Not the first fragment - don't dissect it. */
next_tvb = NULL;
} else {
@@ -1029,7 +1065,7 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
* If this is the first fragment, but not the only fragment,
* tell the next protocol that.
*/
- if (iph.ip_off & IP_MF)
+ if (ip_off & IP_MF)
pinfo->fragmented = TRUE;
else
pinfo->fragmented = FALSE;
@@ -1040,7 +1076,7 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* Just show this as a fragment. */
if (check_col(pinfo->cinfo, COL_INFO))
col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented IP protocol (proto=%s 0x%02x, off=%u)",
- ipprotostr(iph.ip_p), iph.ip_p, (iph.ip_off & IP_OFFSET) * 8);
+ ipprotostr(ip_p), ip_p, (ip_off & IP_OFFSET) * 8);
call_dissector(data_handle, tvb_new_subset(tvb, offset, -1, -1), pinfo,
tree);
pinfo->fragmented = save_fragmented;
@@ -1058,7 +1094,7 @@ dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* Unknown protocol */
if (update_col_info) {
if (check_col(pinfo->cinfo, COL_INFO))
- col_add_fstr(pinfo->cinfo, COL_INFO, "%s (0x%02x)", ipprotostr(iph.ip_p), iph.ip_p);
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s (0x%02x)", ipprotostr(ip_p), ip_p);
}
call_dissector(data_handle,next_tvb, pinfo, tree);
}