#include "config.h"
-#include <string.h>
-#include <glib.h>
-
#include <epan/packet.h>
#include <epan/addr_resolv.h>
#include <epan/ipproto.h>
#include <epan/ip_opts.h>
#include <epan/prefs.h>
#include <epan/conversation_table.h>
+#include <epan/color_dissector_filters.h>
#include <epan/reassemble.h>
#include <epan/etypes.h>
-#include <epan/greproto.h>
#include <epan/ppptypes.h>
#include <epan/llcsaps.h>
#include <epan/aftypes.h>
#include <epan/in_cksum.h>
#include <epan/nlpid.h>
#include <epan/ax25_pids.h>
-#include <epan/tap.h>
-#include <epan/wmem/wmem.h>
#include <epan/decode_as.h>
#include <wiretap/erf.h>
#include "packet-ip.h"
#include "packet-juniper.h"
+#include "packet-sflow.h"
+#include "packet-gre.h"
+#include "packet-l2tp.h"
#ifdef HAVE_GEOIP
#include <GeoIP.h>
static expert_field ei_ip_ttl_lncb = EI_INIT;
static expert_field ei_ip_ttl_too_small = EI_INIT;
static expert_field ei_ip_cipso_tag = EI_INIT;
+static expert_field ei_ip_bogus_ip_version = EI_INIT;
#ifdef HAVE_GEOIP
static void ip_prompt(packet_info *pinfo, gchar* result)
{
- g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "IP protocol %u as", pinfo->ipproto);
+ g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "IP protocol %u as",
+ GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_ip, 0)));
}
static gpointer ip_value(packet_info *pinfo)
{
- return GUINT_TO_POINTER(pinfo->ipproto);
+ return p_get_proto_data(pinfo->pool, pinfo, proto_ip, 0);
}
static const char* ip_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter)
return 1;
}
+static gboolean
+ip_color_filter_valid(packet_info *pinfo)
+{
+ return proto_is_frame_protocol(pinfo->layers, "ip");
+}
+
+static gchar*
+ip_build_color_filter(packet_info *pinfo)
+{
+ return g_strdup_printf("ip.addr eq %s and ip.addr eq %s",
+ address_to_str(pinfo->pool, &pinfo->net_src),
+ address_to_str(pinfo->pool, &pinfo->net_dst));
+}
+
/*
* defragmentation of IPv4
*/
&addresses_reassembly_table_functions);
}
+static void
+ip_defragment_cleanup(void)
+{
+ reassembly_table_destroy(&ip_reassembly_table);
+}
+
void
capture_ip(const guchar *pd, int offset, int len, packet_counts *ld) {
if (!BYTES_ARE_IN_FRAME(offset, len, IPH_MIN_LEN)) {
guint dbnum;
for (dbnum = 0; dbnum < num_dbs; dbnum++) {
- const char *geoip_str = geoip_db_lookup_ipv4(dbnum, ip, NULL);
+ char *geoip_str = geoip_db_lookup_ipv4(dbnum, ip, NULL);
int db_type = geoip_db_type(dbnum);
int geoip_hf, geoip_local_hf;
item_cnt++;
proto_item_append_text(geoip_info_item, "%s%s",
plurality(item_cnt, "", ", "), geoip_str);
+ wmem_free(NULL, geoip_str);
}
}
if (next)
proto_tree_add_ipv4_format_value(tree, hf, tvb, offset, 4, route,
"%s <- (next)",
- ip_to_str((gchar *)&route));
+ tvb_ip_to_str(tvb, offset));
else
proto_tree_add_ipv4(tree, hf, tvb, offset, 4, route);
ti = proto_tree_add_string(tree, hf_host, tvb, offset, 4, get_hostname(route));
"Not evil"
};
+gboolean
+ip_try_dissect(gboolean heur_first, tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, ws_ip *iph)
+{
+ heur_dtbl_entry_t *hdtbl_entry;
+
+ if ((heur_first) && (dissector_try_heuristic(heur_subdissector_list, tvb,
+ pinfo, tree, &hdtbl_entry, iph))) {
+ return TRUE;
+ }
+
+ if (dissector_try_uint_new(ip_dissector_table, iph->ip_p, tvb, pinfo,
+ tree, TRUE, iph)) {
+ return TRUE;
+ }
+
+ if ((!heur_first) && (!dissector_try_heuristic(heur_subdissector_list, tvb,
+ pinfo, tree, &hdtbl_entry,
+ iph))) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static void
-dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
+dissect_ip_v4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
{
proto_tree *ip_tree, *field_tree = NULL;
proto_item *ti, *tf;
int offset = 0, dst_off;
guint hlen, optlen;
guint16 flags;
- guint8 nxt;
guint16 ipsum;
guint16 expected_cksum;
fragment_head *ipfd_head = NULL;
gboolean update_col_info = TRUE;
gboolean save_fragmented;
ws_ip *iph;
- const guchar *src_addr, *dst_addr;
guint32 src32, dst32;
proto_tree *tree;
proto_item *item = NULL, *ttl_item;
proto_tree *checksum_tree;
guint16 ttl;
- heur_dtbl_entry_t *hdtbl_entry;
tree = parent_tree;
iph = (ws_ip *)wmem_alloc(wmem_packet_scope(), sizeof(ws_ip));
col_clear(pinfo->cinfo, COL_INFO);
iph->ip_v_hl = tvb_get_guint8(tvb, offset);
- if ( hi_nibble(iph->ip_v_hl) == 6) {
- call_dissector(ipv6_handle, tvb, pinfo, parent_tree);
- return;
- }
hlen = lo_nibble(iph->ip_v_hl) * 4; /* IP header length, in bytes */
PROTO_ITEM_SET_GENERATED(item);
}
}
- src_addr = tvb_get_ptr(tvb, offset + IPH_SRC, 4);
src32 = tvb_get_ntohl(tvb, offset + IPH_SRC);
- SET_ADDRESS(&pinfo->net_src, AT_IPv4, 4, src_addr);
- SET_ADDRESS(&pinfo->src, AT_IPv4, 4, src_addr);
- SET_ADDRESS(&iph->ip_src, AT_IPv4, 4, src_addr);
+ TVB_SET_ADDRESS(&pinfo->net_src, AT_IPv4, tvb, offset + IPH_SRC, 4);
+ COPY_ADDRESS_SHALLOW(&pinfo->src, &pinfo->net_src);
+ COPY_ADDRESS_SHALLOW(&iph->ip_src, &pinfo->src);
if (tree) {
const char *src_host;
memcpy(&addr, iph->ip_src.data, 4);
src_host = get_hostname(addr);
if (ip_summary_in_tree) {
- proto_item_append_text(ti, ", Src: %s (%s)", src_host,
- ip_to_str((const guint8 *)iph->ip_src.data));
+ proto_item_append_text(ti, ", Src: %s", address_with_resolution_to_str(wmem_packet_scope(), &iph->ip_src));
}
proto_tree_add_ipv4(ip_tree, hf_ip_src, tvb, offset + 12, 4, addr);
item = proto_tree_add_ipv4(ip_tree, hf_ip_addr, tvb, offset + 12, 4, addr);
else
dst_off = 0;
- dst_addr = tvb_get_ptr(tvb, offset + IPH_DST + dst_off, 4);
dst32 = tvb_get_ntohl(tvb, offset + IPH_DST + dst_off);
- SET_ADDRESS(&pinfo->net_dst, AT_IPv4, 4, dst_addr);
- SET_ADDRESS(&pinfo->dst, AT_IPv4, 4, dst_addr);
- SET_ADDRESS(&iph->ip_dst, AT_IPv4, 4, dst_addr);
+ TVB_SET_ADDRESS(&pinfo->net_dst, AT_IPv4, tvb, offset + IPH_DST + dst_off, 4);
+ COPY_ADDRESS_SHALLOW(&pinfo->dst, &pinfo->net_dst);
+ COPY_ADDRESS_SHALLOW(&iph->ip_dst, &pinfo->net_dst);
/* If an IP is destined for an IP address in the Local Network Control Block
* (e.g. 224.0.0.0/24), the packet should never be routed and the TTL would
"Local Network Control Block (see RFC 3171)",
ttl);
}
- } else if (!is_a_multicast_addr(dst32) && iph->ip_ttl < 5 &&
- (iph->ip_p != IP_PROTO_PIM)) {
+ } else if (!is_a_multicast_addr(dst32) &&
+ /* At least BGP should appear here as well */
+ iph->ip_ttl < 5 &&
+ iph->ip_p != IP_PROTO_PIM &&
+ iph->ip_p != IP_PROTO_OSPF) {
expert_add_info_format(pinfo, ttl_item, &ei_ip_ttl_too_small, "\"Time To Live\" only %u", iph->ip_ttl);
}
if (tree) {
const char *dst_host;
- guint32 cur_rt;
memcpy(&addr, iph->ip_dst.data, 4);
dst_host = get_hostname(addr);
- if (dst_off)
- cur_rt = tvb_get_ipv4(tvb, offset + 16);
if (ip_summary_in_tree) {
- proto_item_append_text(ti, ", Dst: %s (%s)", dst_host,
- ip_to_str((const guint8 *)iph->ip_dst.data));
- if (dst_off)
- proto_item_append_text(ti, ", Via: %s (%s)", get_hostname(cur_rt),
- ip_to_str((gchar *)&cur_rt));
+ proto_item_append_text(ti, ", Dst: %s", address_with_resolution_to_str(wmem_packet_scope(), &iph->ip_dst));
}
if (dst_off) {
+ guint32 cur_rt;
+
+ cur_rt = tvb_get_ipv4(tvb, offset + 16);
+ if (ip_summary_in_tree) {
+ proto_item_append_text(ti, ", Via: %s",
+ tvb_address_with_resolution_to_str(wmem_packet_scope(), tvb, AT_IPv4, offset + 16));
+ }
proto_tree_add_ipv4(ip_tree, hf_ip_cur_rt, tvb, offset + 16, 4, cur_rt);
item = proto_tree_add_string(ip_tree, hf_ip_cur_rt_host, tvb,
offset + 16, 4, get_hostname(cur_rt));
IPOPT_EOOL, &IP_OPT_TYPES, &ei_ip_opt_len_invalid, pinfo, field_tree, tf, iph);
}
- pinfo->ipproto = iph->ip_p;
+ p_add_proto_data(pinfo->pool, pinfo, proto_ip, 0, GUINT_TO_POINTER((guint)iph->ip_p));
tap_queue_packet(ip_tap, pinfo, iph);
/* Skip over header + options */
offset += hlen;
- nxt = iph->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
return;
}
+ if (tvb_reported_length(next_tvb) > 0) {
/* Hand off to the next protocol.
XXX - setting the columns only after trying various dissectors means
even be labeled as an IP frame; ideally, if a frame being dissected
throws an exception, it'll be labeled as a mangled frame of the
type in question. */
- if ((try_heuristic_first) && (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, iph))) {
- /* We're good */
- } else if (!dissector_try_uint_new(ip_dissector_table, nxt, next_tvb, pinfo,
- parent_tree, TRUE, iph)) {
- if ((!try_heuristic_first) && (!dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, iph))) {
+ if (!ip_try_dissect(try_heuristic_first, next_tvb, pinfo, parent_tree, iph)) {
/* Unknown protocol */
if (update_col_info) {
col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%u)",
pinfo->fragmented = save_fragmented;
}
+static void
+dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *ip_tree;
+ proto_item *ti, *tf;
+ guint8 version;
+
+ version = tvb_get_guint8(tvb, 0) >> 4;
+
+ if(version == 4){
+ dissect_ip_v4(tvb, pinfo, tree);
+ return;
+ }
+ if(version == 6){
+ call_dissector(ipv6_handle, tvb, pinfo, tree);
+ return;
+ }
+
+ /* Bogus IP version */
+ ti = proto_tree_add_protocol_format(tree, proto_ip, tvb, 0, 1, "Internet Protocol, bogus version (%u)", version);
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "IP");
+ col_clear(pinfo->cinfo, COL_INFO);
+ col_add_fstr(pinfo->cinfo, COL_INFO, "Bogus IP version (%u)", version);
+ ip_tree = proto_item_add_subtree(ti, ett_ip);
+ tf = proto_tree_add_item(ip_tree, hf_ip_version, tvb, 0, 1, ENC_NA);
+ expert_add_info(pinfo, tf, &ei_ip_bogus_ip_version);
+}
+
static gboolean
dissect_ip_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
- length = tvb_length(tvb);
+ length = tvb_captured_length(tvb);
if(length<4){
/* Need at least 4 bytes to make some sort of decision */
return FALSE;
ihl = oct & 0x0f;
version = oct >> 4;
if(version == 6){
- /* TODO: Add IPv6 checks here */
/*
3. IPv6 Header Format
return FALSE;
}
- dissect_ip(tvb, pinfo, tree);
+ dissect_ip_v4(tvb, pinfo, tree);
return TRUE;
}
{ &ei_ip_ttl_lncb, { "ip.ttl.lncb", PI_SEQUENCE, PI_NOTE, "Time To Live", EXPFILL }},
{ &ei_ip_ttl_too_small, { "ip.ttl.too_small", PI_SEQUENCE, PI_NOTE, "Time To Live", EXPFILL }},
{ &ei_ip_cipso_tag, { "ip.cipso.malformed", PI_SEQUENCE, PI_ERROR, "Malformed CIPSO tag", EXPFILL }},
+ { &ei_ip_bogus_ip_version, { "ip.bogus_ip_version", PI_PROTOCOL, PI_ERROR, "Bogus IP version", EXPFILL }},
};
/* Decode As handling */
/* subdissector code */
ip_dissector_table = register_dissector_table("ip.proto", "IP protocol",
FT_UINT8, BASE_DEC);
- register_heur_dissector_list("ip", &heur_subdissector_list);
+ heur_subdissector_list = register_heur_dissector_list("ip");
/* Register configuration options */
ip_module = prefs_register_protocol(proto_ip, NULL);
register_dissector("ip", dissect_ip, proto_ip);
register_init_routine(ip_defragment_init);
+ register_cleanup_routine(ip_defragment_cleanup);
ip_tap = register_tap("ip");
register_decode_as(&ip_da);
- register_conversation_table(proto_ip, TRUE, ip_conversation_packet, ip_hostlist_packet, NULL);
+ register_conversation_table(proto_ip, TRUE, ip_conversation_packet, ip_hostlist_packet);
+ register_color_conversation_filter("ip", "IPv4", ip_color_filter_valid, ip_build_color_filter);
}
void
dissector_add_uint("ax25.pid", AX25_P_IP, ip_handle);
dissector_add_uint("juniper.proto", JUNIPER_PROTO_IP, ip_handle);
dissector_add_uint("juniper.proto", JUNIPER_PROTO_MPLS_IP, ip_handle);
+ dissector_add_uint("pwach.channel_type", 0x21, ip_handle); /* IPv4, RFC4385 clause 6. */
+ dissector_add_uint("sflow_245.header_protocol", SFLOW_245_HEADER_IPv4, ip_handle);
+ dissector_add_uint("l2tp.pw_type", L2TPv3_PROTOCOL_IP, ip_handle);
dissector_add_for_decode_as("udp.port", ip_handle);
+ dissector_add_for_decode_as("pcli.payload", ip_handle);
+ dissector_add_uint("wtap_encap", WTAP_ENCAP_RAW_IP4, ip_handle);
- heur_dissector_add("tipc", dissect_ip_heur, proto_ip);
+ heur_dissector_add("tipc", dissect_ip_heur, "IP over TIPC", "ip_tipc", proto_ip, HEURISTIC_ENABLE);
}
/*
* vi: set shiftwidth=2 tabstop=8 expandtab:
* :indentSize=2:tabSize=8:noTabs=true:
*/
-