summaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-ip.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-ip.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-ip.c')
-rw-r--r--epan/dissectors/packet-ip.c3128
1 files changed, 3128 insertions, 0 deletions
diff --git a/epan/dissectors/packet-ip.c b/epan/dissectors/packet-ip.c
new file mode 100644
index 00000000..355fc6c0
--- /dev/null
+++ b/epan/dissectors/packet-ip.c
@@ -0,0 +1,3128 @@
+/* packet-ip.c
+ * Routines for IP and miscellaneous IP protocol packet disassembly
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * Wednesday, January 17, 2006
+ * Support for the CIPSO IPv4 option
+ * (http://sourceforge.net/docman/display_doc.php?docid=34650&group_id=174379)
+ * by Paul Moore <paul.moore@hp.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include <epan/packet.h>
+#include <epan/capture_dissectors.h>
+#include <epan/addr_resolv.h>
+#include <epan/maxmind_db.h>
+#include <epan/ipproto.h>
+#include <epan/expert.h>
+#include <epan/ip_opts.h>
+#include <epan/prefs.h>
+#include <epan/conversation_table.h>
+#include <epan/conversation_filter.h>
+#include <epan/reassemble.h>
+#include <epan/etypes.h>
+#include <epan/ppptypes.h>
+#include <epan/llcsaps.h>
+#include <epan/aftypes.h>
+#include <epan/arcnet_pids.h>
+#include <epan/in_cksum.h>
+#include <epan/nlpid.h>
+#include <epan/ax25_pids.h>
+#include <epan/decode_as.h>
+#include <epan/proto_data.h>
+#include <epan/exported_pdu.h>
+
+#include <wiretap/erf_record.h>
+#include <wsutil/str_util.h>
+
+#include "packet-ip.h"
+#include "packet-juniper.h"
+#include "packet-sflow.h"
+#include "packet-gre.h"
+#include "packet-l2tp.h"
+#include "packet-vxlan.h"
+#include "packet-mpls.h"
+#include "packet-nsh.h"
+
+void proto_register_ip(void);
+void proto_reg_handoff_ip(void);
+
+static int ip_tap = -1;
+
+static int exported_pdu_tap = -1;
+
+/* Decode the old IPv4 TOS field as the DiffServ DS Field (RFC2474/2475) */
+static gboolean g_ip_dscp_actif = TRUE;
+
+/* Defragment fragmented IP datagrams */
+static gboolean ip_defragment = TRUE;
+
+/* Place IP summary in proto tree */
+static gboolean ip_summary_in_tree = TRUE;
+
+/* Perform IP checksum */
+static gboolean ip_check_checksum = FALSE;
+
+/* Assume TSO and correct zero-length IP packets */
+static gboolean ip_tso_supported = TRUE;
+
+/* Use heuristics to determine subdissector */
+static gboolean try_heuristic_first = FALSE;
+
+/* Interpret the reserved flag as security flag (RFC 3514) */
+static gboolean ip_security_flag = FALSE;
+
+static int proto_ip = -1;
+
+static int proto_ip_option_eol = -1;
+static int proto_ip_option_nop = -1;
+static int proto_ip_option_security = -1;
+static int proto_ip_option_route = -1;
+static int proto_ip_option_timestamp = -1;
+static int proto_ip_option_ext_security = -1;
+static int proto_ip_option_cipso = -1;
+static int proto_ip_option_record_route = -1;
+static int proto_ip_option_sid = -1;
+static int proto_ip_option_source_route = -1;
+static int proto_ip_option_mtu_probe = -1;
+static int proto_ip_option_mtu_reply = -1;
+static int proto_ip_option_traceroute = -1;
+static int proto_ip_option_routeralert = -1;
+static int proto_ip_option_sdb = -1;
+static int proto_ip_option_qs = -1;
+static int hf_ip_version = -1;
+static int hf_ip_hdr_len = -1;
+static int hf_ip_dsfield = -1;
+static int hf_ip_dsfield_dscp = -1;
+static int hf_ip_dsfield_ecn = -1;
+static int hf_ip_tos = -1;
+static int hf_ip_tos_precedence = -1;
+static int hf_ip_tos_delay = -1;
+static int hf_ip_tos_throughput = -1;
+static int hf_ip_tos_reliability = -1;
+static int hf_ip_tos_cost = -1;
+static int hf_ip_len = -1;
+static int hf_ip_id = -1;
+static int hf_ip_dst = -1;
+static int hf_ip_dst_host = -1;
+static int hf_ip_src = -1;
+static int hf_ip_src_host = -1;
+static int hf_ip_addr = -1;
+static int hf_ip_host = -1;
+static int hf_ip_flags = -1;
+static int hf_ip_flags_sf = -1;
+static int hf_ip_flags_rf = -1;
+static int hf_ip_flags_df = -1;
+static int hf_ip_flags_mf = -1;
+static int hf_ip_frag_offset = -1;
+static int hf_ip_ttl = -1;
+static int hf_ip_proto = -1;
+static int hf_ip_checksum = -1;
+static int hf_ip_checksum_calculated = -1;
+static int hf_ip_checksum_status = -1;
+
+/* IP option fields */
+static int hf_ip_opt_type = -1;
+static int hf_ip_opt_type_copy = -1;
+static int hf_ip_opt_type_class = -1;
+static int hf_ip_opt_type_number = -1;
+static int hf_ip_opt_len = -1;
+static int hf_ip_opt_ptr = -1;
+static int hf_ip_opt_sid = -1;
+static int hf_ip_opt_mtu = -1;
+static int hf_ip_opt_id_number = -1;
+static int hf_ip_opt_ohc = -1;
+static int hf_ip_opt_rhc = -1;
+static int hf_ip_opt_originator = -1;
+static int hf_ip_opt_ra = -1;
+static int hf_ip_opt_addr = -1;
+static int hf_ip_opt_padding = -1;
+static int hf_ip_opt_qs_func = -1;
+static int hf_ip_opt_qs_rate = -1;
+static int hf_ip_opt_qs_ttl = -1;
+static int hf_ip_opt_qs_ttl_diff = -1;
+static int hf_ip_opt_qs_unused = -1;
+static int hf_ip_opt_qs_nonce = -1;
+static int hf_ip_opt_qs_reserved = -1;
+static int hf_ip_opt_sec_rfc791_sec = -1;
+static int hf_ip_opt_sec_rfc791_comp = -1;
+static int hf_ip_opt_sec_rfc791_hr = -1;
+static int hf_ip_opt_sec_rfc791_tcc = -1;
+static int hf_ip_opt_sec_cl = -1;
+static int hf_ip_opt_sec_prot_auth_flags = -1;
+static int hf_ip_opt_sec_prot_auth_genser = -1;
+static int hf_ip_opt_sec_prot_auth_siop_esi = -1;
+static int hf_ip_opt_sec_prot_auth_sci = -1;
+static int hf_ip_opt_sec_prot_auth_nsa = -1;
+static int hf_ip_opt_sec_prot_auth_doe = -1;
+static int hf_ip_opt_sec_prot_auth_unassigned = -1;
+static int hf_ip_opt_sec_prot_auth_unassigned2 = -1;
+static int hf_ip_opt_sec_prot_auth_fti = -1;
+static int hf_ip_opt_ext_sec_add_sec_info_format_code = -1;
+static int hf_ip_opt_ext_sec_add_sec_info = -1;
+static int hf_ip_rec_rt = -1;
+static int hf_ip_rec_rt_host = -1;
+static int hf_ip_cur_rt = -1;
+static int hf_ip_cur_rt_host = -1;
+static int hf_ip_src_rt = -1;
+static int hf_ip_src_rt_host = -1;
+static int hf_ip_empty_rt = -1;
+static int hf_ip_empty_rt_host = -1;
+static int hf_ip_cipso_tag_type = -1;
+
+static int hf_ip_fragments = -1;
+static int hf_ip_fragment = -1;
+static int hf_ip_fragment_overlap = -1;
+static int hf_ip_fragment_overlap_conflict = -1;
+static int hf_ip_fragment_multiple_tails = -1;
+static int hf_ip_fragment_too_long_fragment = -1;
+static int hf_ip_fragment_error = -1;
+static int hf_ip_fragment_count = -1;
+static int hf_ip_reassembled_in = -1;
+static int hf_ip_reassembled_length = -1;
+static int hf_ip_reassembled_data = -1;
+
+/* Generated from convert_proto_tree_add_text.pl */
+static int hf_ip_opt_flag = -1;
+static int hf_ip_opt_overflow = -1;
+static int hf_ip_cipso_tag_data = -1;
+static int hf_ip_cipso_sensitivity_level = -1;
+static int hf_ip_cipso_categories = -1;
+static int hf_ip_cipso_doi = -1;
+static int hf_ip_opt_time_stamp = -1;
+static int hf_ip_opt_time_stamp_addr = -1;
+
+static int hf_geoip_country = -1;
+static int hf_geoip_country_iso = -1;
+static int hf_geoip_city = -1;
+static int hf_geoip_as_number = -1;
+static int hf_geoip_as_org = -1;
+static int hf_geoip_latitude = -1;
+static int hf_geoip_longitude = -1;
+static int hf_geoip_src_summary = -1;
+static int hf_geoip_src_country = -1;
+static int hf_geoip_src_country_iso = -1;
+static int hf_geoip_src_city = -1;
+static int hf_geoip_src_as_number = -1;
+static int hf_geoip_src_as_org = -1;
+static int hf_geoip_src_latitude = -1;
+static int hf_geoip_src_longitude = -1;
+static int hf_geoip_dst_summary = -1;
+static int hf_geoip_dst_country = -1;
+static int hf_geoip_dst_country_iso = -1;
+static int hf_geoip_dst_city = -1;
+static int hf_geoip_dst_as_number = -1;
+static int hf_geoip_dst_as_org = -1;
+static int hf_geoip_dst_latitude = -1;
+static int hf_geoip_dst_longitude = -1;
+
+static gint ett_ip = -1;
+static gint ett_ip_dsfield = -1;
+static gint ett_ip_tos = -1;
+static gint ett_ip_flags = -1;
+static gint ett_ip_options = -1;
+static gint ett_ip_option_eool = -1;
+static gint ett_ip_option_nop = -1;
+static gint ett_ip_option_sec = -1;
+static gint ett_ip_option_route = -1;
+static gint ett_ip_option_timestamp = -1;
+static gint ett_ip_option_ext_security = -1;
+static gint ett_ip_option_cipso = -1;
+static gint ett_ip_option_sid = -1;
+static gint ett_ip_option_mtu = -1;
+static gint ett_ip_option_tr = -1;
+static gint ett_ip_option_ra = -1;
+static gint ett_ip_option_sdb = -1;
+static gint ett_ip_option_qs = -1;
+static gint ett_ip_option_other = -1;
+static gint ett_ip_fragments = -1;
+static gint ett_ip_fragment = -1;
+static gint ett_ip_opt_type = -1;
+static gint ett_ip_opt_sec_prot_auth_flags = -1;
+static gint ett_ip_unknown_opt = -1;
+
+static expert_field ei_ip_opt_len_invalid = EI_INIT;
+static expert_field ei_ip_opt_sec_prot_auth_fti = EI_INIT;
+static expert_field ei_ip_extraneous_data = EI_INIT;
+static expert_field ei_ip_opt_ptr_before_address = EI_INIT;
+static expert_field ei_ip_opt_ptr_middle_address = EI_INIT;
+static expert_field ei_ip_subopt_too_long = EI_INIT;
+static expert_field ei_ip_nop = EI_INIT;
+static expert_field ei_ip_bogus_ip_length = EI_INIT;
+static expert_field ei_ip_evil_packet = EI_INIT;
+static expert_field ei_ip_checksum_bad = EI_INIT;
+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;
+static expert_field ei_ip_bogus_header_length = EI_INIT;
+
+static dissector_handle_t ip_handle;
+static dissector_table_t ip_option_table;
+
+static gint ett_geoip_info = -1;
+
+static const fragment_items ip_frag_items = {
+ &ett_ip_fragment,
+ &ett_ip_fragments,
+ &hf_ip_fragments,
+ &hf_ip_fragment,
+ &hf_ip_fragment_overlap,
+ &hf_ip_fragment_overlap_conflict,
+ &hf_ip_fragment_multiple_tails,
+ &hf_ip_fragment_too_long_fragment,
+ &hf_ip_fragment_error,
+ &hf_ip_fragment_count,
+ &hf_ip_reassembled_in,
+ &hf_ip_reassembled_length,
+ &hf_ip_reassembled_data,
+ "IPv4 fragments"
+};
+
+static heur_dissector_list_t heur_subdissector_list;
+
+static dissector_table_t ip_dissector_table;
+
+static dissector_handle_t ipv6_handle;
+static capture_dissector_handle_t ip_cap_handle;
+
+
+/* IP structs and definitions */
+
+const value_string ip_version_vals[] = {
+ { IP_VERSION_NUM_RESERVED, "Reserved" },
+ { IP_VERSION_NUM_INET, "IPv4" },
+ { IP_VERSION_NUM_ST, "ST Datagram" },
+ { IP_VERSION_NUM_INET6, "IPv6" },
+ { IP_VERSION_NUM_TPIX, "TP/IX" },
+ { IP_VERSION_NUM_PIP, "PIP" },
+ { IP_VERSION_NUM_TUBA, "TUBA" },
+ { 0, NULL },
+};
+
+/* Offsets of fields within an IP header. */
+#define IPH_V_HL 0
+#define IPH_TOS 1
+#define IPH_LEN 2
+#define IPH_ID 4
+#define IPH_TTL 6
+#define IPH_OFF 8
+#define IPH_P 9
+#define IPH_SUM 10
+#define IPH_SRC 12
+#define IPH_DST 16
+
+/* Minimum IP header length. */
+#define IPH_MIN_LEN 20
+
+/* IP flags. */
+#define IP_RF 0x8000 /* Flag: "Reserved bit" */
+#define IP_DF 0x4000 /* Flag: "Don't Fragment" */
+#define IP_MF 0x2000 /* Flag: "More Fragments" */
+#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */
+
+/* Differentiated Services Field. See RFCs 2474, 2597, 2598 and 3168. */
+#define IPDSFIELD_DSCP_DEFAULT 0x00
+#define IPDSFIELD_DSCP_LE 0x01
+#define IPDSFIELD_DSCP_CS1 0x08
+#define IPDSFIELD_DSCP_AF11 0x0A
+#define IPDSFIELD_DSCP_AF12 0x0C
+#define IPDSFIELD_DSCP_AF13 0x0E
+#define IPDSFIELD_DSCP_CS2 0x10
+#define IPDSFIELD_DSCP_AF21 0x12
+#define IPDSFIELD_DSCP_AF22 0x14
+#define IPDSFIELD_DSCP_AF23 0x16
+#define IPDSFIELD_DSCP_CS3 0x18
+#define IPDSFIELD_DSCP_AF31 0x1A
+#define IPDSFIELD_DSCP_AF32 0x1C
+#define IPDSFIELD_DSCP_AF33 0x1E
+#define IPDSFIELD_DSCP_CS4 0x20
+#define IPDSFIELD_DSCP_AF41 0x22
+#define IPDSFIELD_DSCP_AF42 0x24
+#define IPDSFIELD_DSCP_AF43 0x26
+#define IPDSFIELD_DSCP_CS5 0x28
+#define IPDSFIELD_VOICE_ADMIT 0x2C
+#define IPDSFIELD_DSCP_EF 0x2E
+#define IPDSFIELD_DSCP_CS6 0x30
+#define IPDSFIELD_DSCP_CS7 0x38
+
+#define IPDSFIELD_ECT_NOT 0x00
+#define IPDSFIELD_ECT_1 0x01
+#define IPDSFIELD_ECT_0 0x02
+#define IPDSFIELD_CE 0x03
+
+/* IP TOS, superseded by the DS Field, RFC 2474. */
+#define IPTOS_TOS_MASK 0x1E
+#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK)
+#define IPTOS_NONE 0x00
+#define IPTOS_LOWCOST 0x02
+#define IPTOS_RELIABILITY 0x04
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_SECURITY 0x1E
+
+#define IPTOS_PREC_MASK 0xE0
+#define IPTOS_PREC_SHIFT 5
+#define IPTOS_PREC(tos) (((tos)&IPTOS_PREC_MASK)>>IPTOS_PREC_SHIFT)
+#define IPTOS_PREC_NETCONTROL 7
+#define IPTOS_PREC_INTERNETCONTROL 6
+#define IPTOS_PREC_CRITIC_ECP 5
+#define IPTOS_PREC_FLASHOVERRIDE 4
+#define IPTOS_PREC_FLASH 3
+#define IPTOS_PREC_IMMEDIATE 2
+#define IPTOS_PREC_PRIORITY 1
+#define IPTOS_PREC_ROUTINE 0
+
+/* IP options */
+#define IPOPT_COPY 0x80
+
+#define IPOPT_CONTROL 0x00
+#define IPOPT_RESERVED1 0x20
+#define IPOPT_MEASUREMENT 0x40
+#define IPOPT_RESERVED2 0x60
+
+/* REF: http://www.iana.org/assignments/ip-parameters */
+/* TODO: Not all of these are implemented. */
+#define IPOPT_EOOL (0 |IPOPT_CONTROL)
+#define IPOPT_NOP (1 |IPOPT_CONTROL)
+#define IPOPT_SEC (2 |IPOPT_COPY|IPOPT_CONTROL) /* RFC 791/1108 */
+#define IPOPT_LSR (3 |IPOPT_COPY|IPOPT_CONTROL)
+#define IPOPT_TS (4 |IPOPT_MEASUREMENT)
+#define IPOPT_ESEC (5 |IPOPT_COPY|IPOPT_CONTROL) /* RFC 1108 */
+#define IPOPT_CIPSO (6 |IPOPT_COPY|IPOPT_CONTROL) /* draft-ietf-cipso-ipsecurity-01 */
+#define IPOPT_RR (7 |IPOPT_CONTROL)
+#define IPOPT_SID (8 |IPOPT_COPY|IPOPT_CONTROL)
+#define IPOPT_SSR (9 |IPOPT_COPY|IPOPT_CONTROL)
+#define IPOPT_ZSU (10|IPOPT_CONTROL) /* Zsu */
+#define IPOPT_MTUP (11|IPOPT_CONTROL) /* RFC 1063 */
+#define IPOPT_MTUR (12|IPOPT_CONTROL) /* RFC 1063 */
+#define IPOPT_FINN (13|IPOPT_COPY|IPOPT_MEASUREMENT) /* Finn */
+#define IPOPT_VISA (14|IPOPT_COPY|IPOPT_CONTROL) /* Estrin */
+#define IPOPT_ENCODE (15|IPOPT_CONTROL) /* VerSteeg */
+#define IPOPT_IMITD (16|IPOPT_COPY|IPOPT_CONTROL) /* Lee */
+#define IPOPT_EIP (17|IPOPT_COPY|IPOPT_CONTROL) /* RFC 1385 */
+#define IPOPT_TR (18|IPOPT_MEASUREMENT) /* RFC 1393 */
+#define IPOPT_ADDEXT (19|IPOPT_COPY|IPOPT_CONTROL) /* Ullmann IPv7 */
+#define IPOPT_RTRALT (20|IPOPT_COPY|IPOPT_CONTROL) /* RFC 2113 */
+#define IPOPT_SDB (21|IPOPT_COPY|IPOPT_CONTROL) /* RFC 1770 Graff */
+#define IPOPT_UN (22|IPOPT_COPY|IPOPT_CONTROL) /* Released 18-Oct-2005 */
+#define IPOPT_DPS (23|IPOPT_COPY|IPOPT_CONTROL) /* Malis */
+#define IPOPT_UMP (24|IPOPT_COPY|IPOPT_CONTROL) /* Farinacci */
+#define IPOPT_QS (25|IPOPT_CONTROL) /* RFC 4782 */
+#define IPOPT_EXP (30|IPOPT_CONTROL) /* RFC 4727 */
+
+
+/* IP option lengths */
+#define IPOLEN_SEC_MIN 3
+#define IPOLEN_LSR_MIN 3
+#define IPOLEN_TS_MIN 4
+#define IPOLEN_ESEC_MIN 3
+#define IPOLEN_CIPSO_MIN 10
+#define IPOLEN_RR_MIN 3
+#define IPOLEN_SID 4
+#define IPOLEN_SSR_MIN 3
+#define IPOLEN_MTU 4
+#define IPOLEN_TR 12
+#define IPOLEN_RA 4
+#define IPOLEN_SDB_MIN 6
+#define IPOLEN_QS 8
+#define IPOLEN_MAX 40
+
+#define IPSEC_RFC791_UNCLASSIFIED 0x0000
+#define IPSEC_RFC791_CONFIDENTIAL 0xF135
+#define IPSEC_RFC791_EFTO 0x789A
+#define IPSEC_RFC791_MMMM 0xBC4D
+#define IPSEC_RFC791_PROG 0x5E26
+#define IPSEC_RFC791_RESTRICTED 0xAF13
+#define IPSEC_RFC791_SECRET 0xD788
+#define IPSEC_RFC791_TOPSECRET 0x6BC5
+#define IPSEC_RFC791_RESERVED1 0x35E2
+#define IPSEC_RFC791_RESERVED2 0x9AF1
+#define IPSEC_RFC791_RESERVED3 0x4D78
+#define IPSEC_RFC791_RESERVED4 0x24BD
+#define IPSEC_RFC791_RESERVED5 0x135E
+#define IPSEC_RFC791_RESERVED6 0x89AF
+#define IPSEC_RFC791_RESERVED7 0xC4D6
+#define IPSEC_RFC791_RESERVED8 0xE26B
+
+#define IPSEC_RESERVED4 0x01
+#define IPSEC_TOPSECRET 0x3D
+#define IPSEC_SECRET 0x5A
+#define IPSEC_CONFIDENTIAL 0x96
+#define IPSEC_RESERVED3 0x66
+#define IPSEC_RESERVED2 0xCC
+#define IPSEC_UNCLASSIFIED 0xAB
+#define IPSEC_RESERVED1 0xF1
+
+#define IPOPT_TS_TSONLY 0 /* timestamps only */
+#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
+#define IPOPT_TS_PRESPEC 3 /* specified modules only */
+
+#define IPLOCAL_NETWRK_CTRL_BLK_VRRP_ADDR 0xE0000012
+#define IPLOCAL_NETWRK_CTRL_BLK_VRRP_TTL 0xFF
+#define IPLOCAL_NETWRK_CTRL_BLK_GLPB_ADDR 0xE0000066
+#define IPLOCAL_NETWRK_CTRL_BLK_GLPB_TTL 0XFF
+#define IPLOCAL_NETWRK_CTRL_BLK_MDNS_ADDR 0xE00000FB
+#define IPLOCAL_NETWRK_CTRL_BLK_MDNS_TTL 0XFF
+#define IPLOCAL_NETWRK_CTRL_BLK_LLMNR_ADDR 0xE00000FC
+
+#define IPLOCAL_NETWRK_CTRL_BLK_ANY_TTL 0x1000 /* larger than max ttl */
+#define IPLOCAL_NETWRK_CTRL_BLK_DEFAULT_TTL 0X01
+
+static void ip_prompt(packet_info *pinfo, gchar* result)
+{
+ snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "IP protocol %u as",
+ GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_ip, pinfo->curr_layer_num)));
+}
+
+static gpointer ip_value(packet_info *pinfo)
+{
+ return p_get_proto_data(pinfo->pool, pinfo, proto_ip, pinfo->curr_layer_num);
+}
+
+static const char* ip_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter)
+{
+ if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_IPv4))
+ return "ip.src";
+
+ if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_IPv4))
+ return "ip.dst";
+
+ if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_IPv4))
+ return "ip.addr";
+
+ return CONV_FILTER_INVALID;
+}
+
+static ct_dissector_info_t ip_ct_dissector_info = {&ip_conv_get_filter_type};
+
+static tap_packet_status
+ip_conversation_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags)
+{
+ conv_hash_t *hash = (conv_hash_t*) pct;
+ hash->flags = flags;
+ const ws_ip4 *iph=(const ws_ip4 *)vip;
+
+ add_conversation_table_data(hash, &iph->ip_src, &iph->ip_dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->abs_ts, &ip_ct_dissector_info, CONVERSATION_NONE);
+
+ return TAP_PACKET_REDRAW;
+}
+
+static const char* ip_endpoint_get_filter_type(endpoint_item_t* endpoint, conv_filter_type_e filter)
+{
+ if ((filter == CONV_FT_ANY_ADDRESS) && (endpoint->myaddress.type == AT_IPv4))
+ return "ip.addr";
+
+ return CONV_FILTER_INVALID;
+}
+
+static et_dissector_info_t ip_endpoint_dissector_info = {&ip_endpoint_get_filter_type};
+
+static tap_packet_status
+ip_endpoint_packet(void *pit, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags)
+{
+ conv_hash_t *hash = (conv_hash_t*) pit;
+ hash->flags = flags;
+ const ws_ip4 *iph=(const ws_ip4 *)vip;
+
+ /* Take two "add" passes per packet, adding for each direction, ensures that all
+ packets are counted properly (even if address is sending to itself)
+ XXX - this could probably be done more efficiently inside endpoint_table */
+ add_endpoint_table_data(hash, &iph->ip_src, 0, TRUE, 1, pinfo->fd->pkt_len, &ip_endpoint_dissector_info, ENDPOINT_NONE);
+ add_endpoint_table_data(hash, &iph->ip_dst, 0, FALSE, 1, pinfo->fd->pkt_len, &ip_endpoint_dissector_info, ENDPOINT_NONE);
+ return TAP_PACKET_REDRAW;
+}
+
+static gboolean
+ip_filter_valid(packet_info *pinfo, void *user_data _U_)
+{
+ return proto_is_frame_protocol(pinfo->layers, "ip");
+}
+
+static gchar*
+ip_build_filter(packet_info *pinfo, void *user_data _U_)
+{
+ return ws_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
+ */
+static reassembly_table ip_reassembly_table;
+
+static gboolean
+capture_ip(const guchar *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header _U_) {
+ if (!BYTES_ARE_IN_FRAME(offset, len, IPH_MIN_LEN))
+ return FALSE;
+
+ capture_dissector_increment_count(cpinfo, proto_ip);
+ return try_capture_dissector("ip.proto", pd[offset + 9], pd, offset+IPH_MIN_LEN, len, cpinfo, pseudo_header);
+}
+
+static void
+add_geoip_info_entry(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, ws_in4_addr ip, int isdst)
+{
+ const mmdb_lookup_t *lookup = maxmind_db_lookup_ipv4(&ip);
+ if (!lookup->found) return;
+
+ wmem_strbuf_t *summary = wmem_strbuf_new(pinfo->pool, "");
+ if (lookup->city) {
+ wmem_strbuf_append(summary, lookup->city);
+ }
+ if (lookup->country_iso) {
+ if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", ");
+ wmem_strbuf_append(summary, lookup->country_iso);
+ } else if (lookup->country) {
+ if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", ");
+ wmem_strbuf_append(summary, lookup->country);
+ }
+ if (lookup->as_number > 0) {
+ if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", ");
+ wmem_strbuf_append_printf(summary, "ASN %u", lookup->as_number);
+ }
+ if (lookup->as_org) {
+ if (wmem_strbuf_get_len(summary) > 0) wmem_strbuf_append(summary, ", ");
+ wmem_strbuf_append(summary, lookup->as_org);
+ }
+
+ int addr_offset = offset + isdst ? IPH_DST : IPH_SRC;
+ int dir_hf = isdst ? hf_geoip_dst_summary : hf_geoip_src_summary;
+ proto_item *geoip_info_item = proto_tree_add_string(tree, dir_hf, tvb, addr_offset, 4, wmem_strbuf_finalize(summary));
+ proto_item_set_generated(geoip_info_item);
+ proto_tree *geoip_info_tree = proto_item_add_subtree(geoip_info_item, ett_geoip_info);
+
+ proto_item *item;
+
+ if (lookup->city) {
+ dir_hf = isdst ? hf_geoip_dst_city : hf_geoip_src_city;
+ item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->city);
+ proto_item_set_generated(item);
+ item = proto_tree_add_string(geoip_info_tree, hf_geoip_city, tvb, addr_offset, 4, lookup->city);
+ proto_item_set_generated(item);
+ }
+
+ if (lookup->country) {
+ dir_hf = isdst ? hf_geoip_dst_country : hf_geoip_src_country;
+ item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->country);
+ proto_item_set_generated(item);
+ item = proto_tree_add_string(geoip_info_tree, hf_geoip_country, tvb, addr_offset, 4, lookup->country);
+ proto_item_set_generated(item);
+ }
+
+ if (lookup->country_iso) {
+ dir_hf = isdst ? hf_geoip_dst_country_iso : hf_geoip_src_country_iso;
+ item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->country_iso);
+ proto_item_set_generated(item);
+ item = proto_tree_add_string(geoip_info_tree, hf_geoip_country_iso, tvb, addr_offset, 4, lookup->country_iso);
+ proto_item_set_generated(item);
+ }
+
+ if (lookup->as_number > 0) {
+ dir_hf = isdst ? hf_geoip_dst_as_number : hf_geoip_src_as_number;
+ item = proto_tree_add_uint(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->as_number);
+ proto_item_set_generated(item);
+ item = proto_tree_add_uint(geoip_info_tree, hf_geoip_as_number, tvb, addr_offset, 4, lookup->as_number);
+ proto_item_set_generated(item);
+ }
+
+ if (lookup->as_org) {
+ dir_hf = isdst ? hf_geoip_dst_as_org : hf_geoip_src_as_org;
+ item = proto_tree_add_string(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->as_org);
+ proto_item_set_generated(item);
+ item = proto_tree_add_string(geoip_info_tree, hf_geoip_as_org, tvb, addr_offset, 4, lookup->as_org);
+ proto_item_set_generated(item);
+ }
+
+ if (lookup->latitude >= -90.0 && lookup->latitude <= 90.0) {
+ dir_hf = isdst ? hf_geoip_dst_latitude : hf_geoip_src_latitude;
+ item = proto_tree_add_double(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->latitude);
+ proto_item_set_generated(item);
+ item = proto_tree_add_double(geoip_info_tree, hf_geoip_latitude, tvb, addr_offset, 4, lookup->latitude);
+ proto_item_set_generated(item);
+ }
+
+ if (lookup->longitude >= -180.0 && lookup->longitude <= 180.0) {
+ dir_hf = isdst ? hf_geoip_dst_longitude : hf_geoip_src_longitude;
+ item = proto_tree_add_double(geoip_info_tree, dir_hf, tvb, addr_offset, 4, lookup->longitude);
+ proto_item_set_generated(item);
+ item = proto_tree_add_double(geoip_info_tree, hf_geoip_longitude, tvb, addr_offset, 4, lookup->longitude);
+ proto_item_set_generated(item);
+ }
+}
+
+static void
+add_geoip_info(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, guint32 src32,
+ guint32 dst32)
+{
+ add_geoip_info_entry(tree, pinfo, tvb, offset, g_htonl(src32), FALSE);
+ add_geoip_info_entry(tree, pinfo, tvb, offset, g_htonl(dst32), TRUE);
+}
+
+const value_string ipopt_type_class_vals[] = {
+ {(IPOPT_CONTROL & IPOPT_CLASS_MASK) >> 5, "Control"},
+ {(IPOPT_RESERVED1 & IPOPT_CLASS_MASK) >> 5, "Reserved for future use"},
+ {(IPOPT_MEASUREMENT & IPOPT_CLASS_MASK) >> 5, "Debugging and measurement"},
+ {(IPOPT_RESERVED2 & IPOPT_CLASS_MASK) >> 5, "Reserved for future use"},
+ {0, NULL}
+};
+
+const value_string ipopt_type_number_vals[] = {
+ {IPOPT_EOOL & IPOPT_NUMBER_MASK, "End of Option List (EOL)"},
+ {IPOPT_NOP & IPOPT_NUMBER_MASK, "No-Operation (NOP)"},
+ {IPOPT_SEC & IPOPT_NUMBER_MASK, "Security"},
+ {IPOPT_LSR & IPOPT_NUMBER_MASK, "Loose source route"},
+ {IPOPT_TS & IPOPT_NUMBER_MASK, "Time stamp"},
+ {IPOPT_ESEC & IPOPT_NUMBER_MASK, "Extended security"},
+ {IPOPT_CIPSO & IPOPT_NUMBER_MASK, "Commercial IP security option"},
+ {IPOPT_RR & IPOPT_NUMBER_MASK, "Record route"},
+ {IPOPT_SID & IPOPT_NUMBER_MASK, "Stream identifier"},
+ {IPOPT_SSR & IPOPT_NUMBER_MASK, "Strict source route"},
+ {IPOPT_ZSU & IPOPT_NUMBER_MASK, "Experimental Measurement"},
+ {IPOPT_MTUP & IPOPT_NUMBER_MASK, "MTU probe"},
+ {IPOPT_MTUR & IPOPT_NUMBER_MASK, "MTU Reply"},
+ {IPOPT_FINN & IPOPT_NUMBER_MASK, "Experimental Flow Control"},
+ {IPOPT_VISA & IPOPT_NUMBER_MASK, "Experimental Access Control"},
+ {IPOPT_ENCODE & IPOPT_NUMBER_MASK, "Ask Estrin"},
+ {IPOPT_IMITD & IPOPT_NUMBER_MASK, "IMI Traffic Descriptor"},
+ {IPOPT_EIP & IPOPT_NUMBER_MASK, "Extended Internet Protocol"},
+ {IPOPT_TR & IPOPT_NUMBER_MASK, "Traceroute"},
+ {IPOPT_ADDEXT & IPOPT_NUMBER_MASK, "Address Extension"},
+ {IPOPT_RTRALT & IPOPT_NUMBER_MASK, "Router Alert"},
+ {IPOPT_SDB & IPOPT_NUMBER_MASK, "Selective Directed Broadcast"},
+ {IPOPT_UN & IPOPT_NUMBER_MASK, "Unassigned"},
+ {IPOPT_DPS & IPOPT_NUMBER_MASK, "Dynamic Packet State"},
+ {IPOPT_UMP & IPOPT_NUMBER_MASK, "Upstream Multicast Packet"},
+ {IPOPT_QS & IPOPT_NUMBER_MASK, "Quick-Start"},
+ {IPOPT_EXP & IPOPT_NUMBER_MASK, "RFC 3692-style experiment"},
+ {0, NULL}
+};
+
+static void
+dissect_ipopt_type(tvbuff_t *tvb, int offset, proto_tree *tree)
+{
+ proto_tree *type_tree;
+ proto_item *ti;
+
+ ti = proto_tree_add_item(tree, hf_ip_opt_type, tvb, offset, 1, ENC_NA);
+ type_tree = proto_item_add_subtree(ti, ett_ip_opt_type);
+ proto_tree_add_item(type_tree, hf_ip_opt_type_copy, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(type_tree, hf_ip_opt_type_class, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(type_tree, hf_ip_opt_type_number, tvb, offset, 1, ENC_NA);
+}
+
+static proto_tree*
+ip_fixed_option_header(proto_tree* tree, packet_info *pinfo, tvbuff_t *tvb, int proto, int ett, proto_item** ti, guint len, guint optlen)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+
+ *ti = proto_tree_add_item(tree, proto, tvb, 0, optlen, ENC_NA);
+ field_tree = proto_item_add_subtree(*ti, ett);
+ proto_item_append_text(*ti, " (%u bytes)", len);
+
+ dissect_ipopt_type(tvb, 0, field_tree);
+ tf = proto_tree_add_item(field_tree, hf_ip_opt_len, tvb, 1, 1, ENC_NA);
+
+ if (len != optlen) {
+ /* Bogus - option length isn't what it's supposed to be for this option. */
+ expert_add_info_format(pinfo, tf, &ei_ip_opt_len_invalid,
+ "%s (with option length = %u byte%s; should be %u)",
+ proto_get_protocol_short_name(find_protocol_by_id(proto)),
+ optlen, plurality(optlen, "", "s"), len);
+ }
+
+ return field_tree;
+}
+
+static proto_tree*
+ip_var_option_header(proto_tree* tree, packet_info *pinfo, tvbuff_t *tvb, int proto, int ett, proto_item** ti, guint optlen)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+
+ *ti = proto_tree_add_item(tree, proto, tvb, 0, optlen, ENC_NA);
+ field_tree = proto_item_add_subtree(*ti, ett);
+ proto_item_append_text(*ti, " (%u bytes)", optlen);
+
+ dissect_ipopt_type(tvb, 0, field_tree);
+ tf = proto_tree_add_item(field_tree, hf_ip_opt_len, tvb, 1, 1, ENC_NA);
+ if (optlen > IPOLEN_MAX)
+ expert_add_info(pinfo, tf, &ei_ip_opt_len_invalid);
+
+ return field_tree;
+}
+
+static const value_string secl_rfc791_vals[] = {
+ {IPSEC_RFC791_UNCLASSIFIED, "Unclassified"},
+ {IPSEC_RFC791_CONFIDENTIAL, "Confidential"},
+ {IPSEC_RFC791_EFTO, "EFTO" },
+ {IPSEC_RFC791_MMMM, "MMMM" },
+ {IPSEC_RFC791_PROG, "PROG" },
+ {IPSEC_RFC791_RESTRICTED, "Restricted" },
+ {IPSEC_RFC791_SECRET, "Secret" },
+ {IPSEC_RFC791_TOPSECRET, "Top secret" },
+ {IPSEC_RFC791_RESERVED1, "Reserved" },
+ {IPSEC_RFC791_RESERVED2, "Reserved" },
+ {IPSEC_RFC791_RESERVED3, "Reserved" },
+ {IPSEC_RFC791_RESERVED4, "Reserved" },
+ {IPSEC_RFC791_RESERVED5, "Reserved" },
+ {IPSEC_RFC791_RESERVED6, "Reserved" },
+ {IPSEC_RFC791_RESERVED7, "Reserved" },
+ {IPSEC_RFC791_RESERVED8, "Reserved" },
+ {0, NULL }
+};
+
+static const value_string sec_cl_vals[] = {
+ {IPSEC_RESERVED4, "Reserved 4" },
+ {IPSEC_TOPSECRET, "Top secret" },
+ {IPSEC_SECRET, "Secret" },
+ {IPSEC_CONFIDENTIAL, "Confidential"},
+ {IPSEC_RESERVED3, "Reserved 3" },
+ {IPSEC_RESERVED2, "Reserved 2" },
+ {IPSEC_UNCLASSIFIED, "Unclassified"},
+ {IPSEC_RESERVED1, "Reserved 1" },
+ {0, NULL }
+};
+
+static const true_false_string ip_opt_sec_prot_auth_flag_tfs = {
+ "Datagram protected in accordance with its rules",
+ "Datagram not protected in accordance with its rules"
+};
+
+static const true_false_string ip_opt_sec_prot_auth_fti_tfs = {
+ "Additional octet present",
+ "Final octet"
+};
+
+static int * const ip_opt_sec_prot_auth_fields_byte_1[] = {
+ &hf_ip_opt_sec_prot_auth_genser,
+ &hf_ip_opt_sec_prot_auth_siop_esi,
+ &hf_ip_opt_sec_prot_auth_sci,
+ &hf_ip_opt_sec_prot_auth_nsa,
+ &hf_ip_opt_sec_prot_auth_doe,
+ &hf_ip_opt_sec_prot_auth_unassigned,
+ &hf_ip_opt_sec_prot_auth_fti,
+ NULL
+};
+
+static int * const ip_opt_sec_prot_auth_fields_byte_n[] = {
+ &hf_ip_opt_sec_prot_auth_unassigned2,
+ &hf_ip_opt_sec_prot_auth_fti,
+ NULL
+};
+static int
+dissect_ipopt_security(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+ guint val;
+ guint curr_offset = 2;
+ guint optlen = tvb_reported_length(tvb);
+
+ field_tree = ip_var_option_header(tree, pinfo, tvb, proto_ip_option_security, ett_ip_option_sec, &tf, optlen);
+
+ if (optlen == 11) {
+ /* Analyze payload start to decide whether it should be dissected
+ according to RFC 791 or RFC 1108 */
+ val = tvb_get_ntohs(tvb, curr_offset);
+ if (try_val_to_str(val, secl_rfc791_vals)) {
+ /* Dissect as RFC 791 */
+ proto_tree_add_item(field_tree, hf_ip_opt_sec_rfc791_sec,
+ tvb, curr_offset, 2, ENC_BIG_ENDIAN);
+ curr_offset += 2;
+ proto_tree_add_item(field_tree, hf_ip_opt_sec_rfc791_comp,
+ tvb, curr_offset, 2, ENC_BIG_ENDIAN);
+ curr_offset += 2;
+ proto_tree_add_item(field_tree, hf_ip_opt_sec_rfc791_hr,
+ tvb, curr_offset, 2, ENC_ASCII);
+ curr_offset += 2;
+ proto_tree_add_item(field_tree, hf_ip_opt_sec_rfc791_tcc,
+ tvb, curr_offset, 3, ENC_ASCII);
+ return curr_offset;
+ }
+ }
+
+ /* Dissect as RFC 108 */
+ proto_tree_add_item(field_tree, hf_ip_opt_sec_cl, tvb, curr_offset, 1, ENC_BIG_ENDIAN);
+ curr_offset++;
+ if (curr_offset >= optlen) {
+ return curr_offset;
+ }
+ val = tvb_get_guint8(tvb, curr_offset);
+ proto_tree_add_bitmask(field_tree, tvb, curr_offset, hf_ip_opt_sec_prot_auth_flags,
+ ett_ip_opt_sec_prot_auth_flags, ip_opt_sec_prot_auth_fields_byte_1,
+ ENC_BIG_ENDIAN);
+ curr_offset++;
+ while (val & 0x01) {
+ if ((val & 0x01) && (curr_offset == optlen)) {
+ expert_add_info(pinfo, tf, &ei_ip_opt_sec_prot_auth_fti);
+ break;
+ }
+ val = tvb_get_guint8(tvb, curr_offset);
+ proto_tree_add_bitmask(field_tree, tvb, curr_offset, hf_ip_opt_sec_prot_auth_flags,
+ ett_ip_opt_sec_prot_auth_flags, ip_opt_sec_prot_auth_fields_byte_n,
+ ENC_BIG_ENDIAN);
+ curr_offset++;
+ }
+ if (curr_offset < optlen) {
+ expert_add_info(pinfo, tf, &ei_ip_extraneous_data);
+ }
+
+ return curr_offset;
+}
+
+static int
+dissect_ipopt_ext_security(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+ guint curr_offset = 2;
+ gint remaining;
+ gint optlen = tvb_reported_length(tvb);
+
+ field_tree = ip_var_option_header(tree, pinfo, tvb, proto_ip_option_ext_security, ett_ip_option_ext_security, &tf, optlen);
+
+ proto_tree_add_item(field_tree, hf_ip_opt_ext_sec_add_sec_info_format_code, tvb, curr_offset, 1, ENC_BIG_ENDIAN);
+ curr_offset++;
+ remaining = optlen - curr_offset;
+ if (remaining > 0) {
+ proto_tree_add_item(field_tree, hf_ip_opt_ext_sec_add_sec_info, tvb, curr_offset, remaining, ENC_NA);
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+/* USHRT_MAX can hold at most 5 (base 10) digits (6 for the NULL byte) */
+#define USHRT_MAX_STRLEN 6
+
+/* Maximum CIPSO tag length:
+ * (IP hdr max)60 - (IPv4 hdr std)20 - (CIPSO base)6 = 34 */
+#define CIPSO_TAG_LEN_MAX 34
+
+/* The Commercial IP Security Option (CIPSO) is defined in IETF draft
+ * draft-ietf-cipso-ipsecurity-01.txt and FIPS 188, a copy of both documents
+ * can be found at the NetLabel project page, http://netlabel.sf.net or at
+ * https://tools.ietf.org/html/draft-ietf-cipso-ipsecurity-01 */
+static const value_string cipso_tag_type_vals[] = {
+ {0, "Padding"},
+ {1, "Restrictive Category Bitmap"},
+ {2, "Enumerated Categories"},
+ {5, "Ranged Categories"},
+ {6, "Permissive Categories"},
+ {7, "Free Form"},
+
+ { 0, NULL }
+};
+
+static int
+dissect_ipopt_cipso(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ proto_tree *field_tree;
+ proto_item *tf, *tag_item;
+ guint tagtype, taglen;
+ gint offset = 2,
+ optlen = tvb_reported_length(tvb);
+ int offset_max = optlen;
+
+ field_tree = ip_var_option_header(tree, pinfo, tvb, proto_ip_option_cipso, ett_ip_option_cipso, &tf, optlen);
+
+ proto_tree_add_item(field_tree, hf_ip_cipso_doi, tvb, offset, 4, ENC_BIG_ENDIAN);
+ offset += 4;
+
+ /* loop through all of the tags in the CIPSO option */
+ while (offset < offset_max) {
+ tagtype = tvb_get_guint8(tvb, offset);
+ tag_item = proto_tree_add_item(field_tree, hf_ip_cipso_tag_type, tvb, offset, 1, ENC_NA);
+
+ if ((offset + 1) < offset_max)
+ taglen = tvb_get_guint8(tvb, offset + 1);
+ else
+ taglen = 1;
+
+ switch (tagtype) {
+ case 0:
+ /* padding - skip this tag */
+ offset += 1;
+ continue;
+ case 1:
+ /* restrictive bitmap, see CIPSO draft section 3.4.2 for tag format */
+ if ((taglen < 4) || (taglen > CIPSO_TAG_LEN_MAX) ||
+ ((offset + (int)taglen - 1) > offset_max)) {
+ expert_add_info(pinfo, tag_item, &ei_ip_cipso_tag);
+ return offset;
+ }
+
+ /* skip past alignment octet */
+ offset += 3;
+
+ proto_tree_add_item(field_tree, hf_ip_cipso_sensitivity_level, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ if (taglen > 4) {
+ guint bit_spot = 0;
+ guint byte_spot = 0;
+ unsigned char bitmask;
+ char *cat_str;
+ char *cat_str_tmp = (char *)wmem_alloc(pinfo->pool, USHRT_MAX_STRLEN);
+ size_t cat_str_len;
+ const guint8 *val_ptr = tvb_get_ptr(tvb, offset, taglen - 4);
+
+ /* this is just a guess regarding string size, but we grow it below
+ * if needed */
+ cat_str_len = 256;
+ cat_str = (char *)wmem_alloc0(pinfo->pool, cat_str_len);
+
+ /* we checked the length above so the highest category value
+ * possible here is 240 */
+ while (byte_spot < (taglen - 4)) {
+ bitmask = 0x80;
+ bit_spot = 0;
+ while (bit_spot < 8) {
+ if (val_ptr[byte_spot] & bitmask) {
+ snprintf(cat_str_tmp, USHRT_MAX_STRLEN, "%u",
+ byte_spot * 8 + bit_spot);
+ if (cat_str_len < (strlen(cat_str) + 2 + USHRT_MAX_STRLEN)) {
+ char *cat_str_new;
+
+ while (cat_str_len < (strlen(cat_str) + 2 + USHRT_MAX_STRLEN))
+ cat_str_len += cat_str_len;
+ cat_str_new = (char *)wmem_alloc(pinfo->pool, cat_str_len);
+ (void) g_strlcpy(cat_str_new, cat_str, cat_str_len);
+ cat_str_new[cat_str_len - 1] = '\0';
+ cat_str = cat_str_new;
+ }
+ if (cat_str[0] != '\0')
+ (void) g_strlcat(cat_str, ",", cat_str_len);
+ (void) g_strlcat(cat_str, cat_str_tmp, cat_str_len);
+ }
+ bit_spot++;
+ bitmask >>= 1;
+ }
+ byte_spot++;
+ }
+
+ if (cat_str)
+ proto_tree_add_string(field_tree, hf_ip_cipso_categories, tvb, offset, taglen - 4, cat_str);
+ else
+ proto_tree_add_string(field_tree, hf_ip_cipso_categories, tvb, offset, taglen - 4, "ERROR PARSING CATEGORIES");
+ offset += taglen - 4;
+ }
+ break;
+ case 2:
+ /* enumerated categories, see CIPSO draft section 3.4.3 for tag format */
+ if ((taglen < 4) || (taglen > CIPSO_TAG_LEN_MAX) ||
+ ((offset + (int)taglen - 1) > offset_max)) {
+ expert_add_info(pinfo, tag_item, &ei_ip_cipso_tag);
+ return offset;
+ }
+
+ /* skip past alignment octet */
+ offset += 3;
+
+ /* sensitivity level */
+ proto_tree_add_item(field_tree, hf_ip_cipso_sensitivity_level, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ if (taglen > 4) {
+ int offset_max_cat = offset + taglen - 4;
+ char *cat_str = (char *)wmem_alloc0(pinfo->pool, USHRT_MAX_STRLEN * 15);
+ char *cat_str_tmp = (char *)wmem_alloc(pinfo->pool, USHRT_MAX_STRLEN);
+
+ while ((offset + 2) <= offset_max_cat) {
+ snprintf(cat_str_tmp, USHRT_MAX_STRLEN, "%u",
+ tvb_get_ntohs(tvb, offset));
+ offset += 2;
+ if (cat_str[0] != '\0')
+ (void) g_strlcat(cat_str, ",", USHRT_MAX_STRLEN * 15);
+ (void) g_strlcat(cat_str, cat_str_tmp, USHRT_MAX_STRLEN * 15);
+ }
+
+ proto_tree_add_string(field_tree, hf_ip_cipso_categories, tvb, offset - taglen + 4, taglen - 4, cat_str);
+ }
+ break;
+ case 5:
+ /* ranged categories, see CIPSO draft section 3.4.4 for tag format */
+ if ((taglen < 4) || (taglen > CIPSO_TAG_LEN_MAX) ||
+ ((offset + (int)taglen - 1) > offset_max)) {
+ expert_add_info(pinfo, tag_item, &ei_ip_cipso_tag);
+ return offset;
+ }
+
+ /* skip past alignment octet */
+ offset += 3;
+
+ /* sensitivity level */
+ proto_tree_add_item(field_tree, hf_ip_cipso_sensitivity_level, tvb, offset, 1, ENC_NA);
+ offset += 1;
+
+ if (taglen > 4) {
+ guint16 cat_low, cat_high;
+ int offset_max_cat = offset + taglen - 4;
+ char *cat_str = (char *)wmem_alloc0(pinfo->pool, USHRT_MAX_STRLEN * 16);
+ char *cat_str_tmp = (char *)wmem_alloc(pinfo->pool, USHRT_MAX_STRLEN * 2);
+
+ while ((offset + 2) <= offset_max_cat) {
+ cat_high = tvb_get_ntohs(tvb, offset);
+ if ((offset + 4) <= offset_max_cat) {
+ cat_low = tvb_get_ntohs(tvb, offset + 2);
+ offset += 4;
+ } else {
+ cat_low = 0;
+ offset += 2;
+ }
+ if (cat_low != cat_high)
+ snprintf(cat_str_tmp, USHRT_MAX_STRLEN * 2, "%u-%u",
+ cat_high, cat_low);
+ else
+ snprintf(cat_str_tmp, USHRT_MAX_STRLEN * 2, "%u", cat_high);
+
+ if (cat_str[0] != '\0')
+ (void) g_strlcat(cat_str, ",", USHRT_MAX_STRLEN * 16);
+ (void) g_strlcat(cat_str, cat_str_tmp, USHRT_MAX_STRLEN * 16);
+ }
+
+ proto_tree_add_string(field_tree, hf_ip_cipso_categories, tvb, offset - taglen + 4, taglen - 4, cat_str);
+ }
+ break;
+ case 6:
+ /* permissive categories, see FIPS 188 section 6.9 for tag format */
+ if ((taglen < 4) || (taglen > CIPSO_TAG_LEN_MAX) ||
+ ((offset + (int)taglen - 1) > offset_max)) {
+ expert_add_info(pinfo, tag_item, &ei_ip_cipso_tag);
+ return offset;
+ }
+
+ proto_tree_add_item(field_tree, hf_ip_cipso_tag_data, tvb, offset + 2, taglen - 2, ENC_NA);
+ offset += taglen;
+ break;
+ case 7:
+ /* free form, see FIPS 188 section 6.10 for tag format */
+ if ((taglen < 2) || (taglen > CIPSO_TAG_LEN_MAX) ||
+ ((offset + (int)taglen - 1) > offset_max)) {
+ expert_add_info(pinfo, tag_item, &ei_ip_cipso_tag);
+ return offset;
+ }
+
+ proto_tree_add_item(field_tree, hf_ip_cipso_tag_data, tvb, offset + 2, taglen - 2, ENC_NA);
+ offset += taglen;
+ break;
+ default:
+ /* unknown tag - stop parsing this IPv4 option */
+ if ((offset + 1) <= offset_max) {
+ taglen = tvb_get_guint8(tvb, offset + 1);
+ proto_item_append_text(tag_item, " (%u bytes)", taglen);
+ return offset;
+ }
+ return offset;
+ }
+ }
+
+ return offset;
+}
+
+static void
+dissect_option_route(proto_tree *tree, tvbuff_t *tvb, int offset, int hf,
+ int hf_host, gboolean next)
+{
+ proto_item *ti;
+ guint32 route;
+
+ route = tvb_get_ipv4(tvb, offset);
+ if (next)
+ proto_tree_add_ipv4_format_value(tree, hf, tvb, offset, 4, route,
+ "%s <- (next)",
+ tvb_ip_to_str(wmem_packet_scope(), 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));
+ proto_item_set_generated(ti);
+ proto_item_set_hidden(ti);
+}
+
+static int
+dissect_ipopt_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int proto, int optlen_min)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+ guint8 len, ptr;
+ int optoffset = 0;
+ gint offset = 0,
+ optlen = tvb_reported_length(tvb);
+
+ field_tree = ip_var_option_header(tree, pinfo, tvb, proto, ett_ip_option_route, &tf, optlen);
+
+ ptr = tvb_get_guint8(tvb, offset + 2);
+ tf = proto_tree_add_item(field_tree, hf_ip_opt_ptr, tvb, offset + 2, 1, ENC_NA);
+ if ((ptr < (optlen_min + 1)) || (ptr & 3)) {
+ if (ptr < (optlen_min + 1)) {
+ expert_add_info(pinfo, tf, &ei_ip_opt_ptr_before_address);
+ }
+ else {
+ expert_add_info(pinfo, tf, &ei_ip_opt_ptr_middle_address);
+ }
+ return optlen_min;
+ }
+
+ len = optlen;
+ optoffset = 3; /* skip past type, length and pointer */
+ for (optlen -= 3; optlen > 0; optlen -= 4, optoffset += 4) {
+ if (optlen < 4) {
+ expert_add_info(pinfo, tf, &ei_ip_subopt_too_long);
+ break;
+ }
+
+ if (ptr > len) {
+ /* This is a recorded route */
+ dissect_option_route(field_tree, tvb, offset + optoffset, hf_ip_rec_rt,
+ hf_ip_rec_rt_host, FALSE);
+ } else if (optoffset == (len - 4)) {
+ /* This is the destination */
+ proto_item *item;
+ guint32 addr;
+ const char *dst_host;
+
+ addr = tvb_get_ipv4(tvb, offset + optoffset);
+ dst_host = get_hostname(addr);
+ proto_tree_add_ipv4(field_tree, hf_ip_dst, tvb,
+ offset + optoffset, 4, addr);
+ item = proto_tree_add_ipv4(field_tree, hf_ip_addr, tvb,
+ offset + optoffset, 4, addr);
+ proto_item_set_hidden(item);
+ item = proto_tree_add_string(field_tree, hf_ip_dst_host, tvb,
+ offset + optoffset, 4, dst_host);
+ proto_item_set_generated(item);
+ proto_item_set_hidden(item);
+ item = proto_tree_add_string(field_tree, hf_ip_host, tvb,
+ offset + optoffset, 4, dst_host);
+ proto_item_set_generated(item);
+ proto_item_set_hidden(item);
+ } else if ((optoffset + 1) < ptr) {
+ /* This is also a recorded route */
+ dissect_option_route(field_tree, tvb, offset + optoffset, hf_ip_rec_rt,
+ hf_ip_rec_rt_host, FALSE);
+ } else if ((optoffset + 1) == ptr) {
+ /* This is the next source route. TODO: Should we use separate hf's
+ * for this, such as hf_ip_next_rt and hf_ip_next_rt_host and avoid
+ * having to pass TRUE/FALSE to dissect_option_route()? */
+ dissect_option_route(field_tree, tvb, offset + optoffset, hf_ip_src_rt,
+ hf_ip_src_rt_host, TRUE);
+ } else {
+ /* This must be a source route */
+ dissect_option_route(field_tree, tvb, offset + optoffset, hf_ip_src_rt,
+ hf_ip_src_rt_host, FALSE);
+ }
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_ipopt_loose_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ return dissect_ipopt_route(tvb, pinfo, tree, proto_ip_option_route, IPOLEN_LSR_MIN);
+}
+
+static int
+dissect_ipopt_source_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ return dissect_ipopt_route(tvb, pinfo, tree, proto_ip_option_source_route, IPOLEN_SSR_MIN);
+
+}
+
+static int
+dissect_ipopt_record_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+ guint8 len, ptr;
+ int optoffset = 0;
+ gint offset = 0,
+ optlen = tvb_reported_length(tvb);
+
+ field_tree = ip_var_option_header(tree, pinfo, tvb, proto_ip_option_record_route, ett_ip_option_route, &tf, optlen);
+
+ ptr = tvb_get_guint8(tvb, offset + 2);
+ tf = proto_tree_add_item(field_tree, hf_ip_opt_ptr, tvb, offset + 2, 1, ENC_NA);
+
+ if ((ptr < (IPOLEN_RR_MIN + 1)) || (ptr & 3)) {
+ if (ptr < (IPOLEN_RR_MIN + 1)) {
+ expert_add_info(pinfo, tf, &ei_ip_opt_ptr_before_address);
+ }
+ else {
+ expert_add_info(pinfo, tf, &ei_ip_opt_ptr_middle_address);
+ }
+ return IPOLEN_RR_MIN;
+ }
+
+ len = optlen;
+ optoffset = 3; /* skip past type, length and pointer */
+ for (optlen -= 3; optlen > 0; optlen -= 4, optoffset += 4) {
+ if (optlen < 4) {
+ expert_add_info(pinfo, tf, &ei_ip_subopt_too_long);
+ break;
+ }
+
+ if (ptr > len) {
+ /* The recorded route data area is full. */
+ dissect_option_route(field_tree, tvb, offset + optoffset, hf_ip_rec_rt,
+ hf_ip_rec_rt_host, FALSE);
+ } else if ((optoffset + 1) < ptr) {
+ /* This is a recorded route */
+ dissect_option_route(field_tree, tvb, offset + optoffset, hf_ip_rec_rt,
+ hf_ip_rec_rt_host, FALSE);
+ } else if ((optoffset + 1) == ptr) {
+ /* This is the next available slot. TODO: Should we use separate hf's
+ * for this, such as hf_ip_next_rt and hf_ip_next_rt_host and avoid
+ * having to pass TRUE/FALSE to dissect_option_route()? */
+ dissect_option_route(field_tree, tvb, offset + optoffset, hf_ip_empty_rt,
+ hf_ip_empty_rt_host, TRUE);
+ } else {
+ /* This must be an available slot too. */
+ dissect_option_route(field_tree, tvb, offset + optoffset, hf_ip_empty_rt,
+ hf_ip_empty_rt_host, FALSE);
+ }
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+/* Stream Identifier */
+static int
+dissect_ipopt_sid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+
+ field_tree = ip_fixed_option_header(tree, pinfo, tvb, proto_ip_option_sid, ett_ip_option_sid, &tf, IPOLEN_SID, tvb_reported_length(tvb));
+
+ proto_tree_add_item(field_tree, hf_ip_opt_sid, tvb, 2, 2, ENC_BIG_ENDIAN);
+ return tvb_captured_length(tvb);
+}
+
+/* RFC 1063: MTU Probe and MTU Reply */
+static int
+dissect_ipopt_mtu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int proto)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+
+ field_tree = ip_fixed_option_header(tree, pinfo, tvb, proto, ett_ip_option_mtu, &tf, IPOLEN_MTU, tvb_reported_length(tvb));
+
+ proto_tree_add_item(field_tree, hf_ip_opt_mtu, tvb, 2, 2, ENC_BIG_ENDIAN);
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_ipopt_mtu_probe(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ return dissect_ipopt_mtu(tvb, pinfo, tree, proto_ip_option_mtu_probe);
+}
+
+static int
+dissect_ipopt_mtu_reply(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ return dissect_ipopt_mtu(tvb, pinfo, tree, proto_ip_option_mtu_reply);
+}
+
+/* RFC 1393: Traceroute */
+static int
+dissect_ipopt_tr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+ gint offset = 2;
+
+ field_tree = ip_fixed_option_header(tree, pinfo, tvb, proto_ip_option_traceroute, ett_ip_option_tr, &tf, IPOLEN_TR, tvb_reported_length(tvb));
+
+ proto_tree_add_item(field_tree, hf_ip_opt_id_number, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(field_tree, hf_ip_opt_ohc, tvb, offset + 2, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(field_tree, hf_ip_opt_rhc, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item(field_tree, hf_ip_opt_originator, tvb, offset + 6, 4, ENC_BIG_ENDIAN);
+ return tvb_captured_length(tvb);
+}
+
+static const value_string ipopt_timestamp_flag_vals[] = {
+ {IPOPT_TS_TSONLY, "Time stamps only" },
+ {IPOPT_TS_TSANDADDR, "Time stamp and address" },
+ {IPOPT_TS_PRESPEC, "Time stamps for prespecified addresses"},
+ {0, NULL }};
+
+static int
+dissect_ipopt_timestamp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+ int ptr;
+ int optoffset = 0;
+ int flg;
+ guint32 addr;
+ gint offset = 0,
+ optlen = tvb_reported_length(tvb);
+
+ field_tree = ip_var_option_header(tree, pinfo, tvb, proto_ip_option_timestamp, ett_ip_option_timestamp, &tf, optlen);
+
+ optoffset += 2; /* skip past type and length */
+ optlen -= 2; /* subtract size of type and length */
+
+ ptr = tvb_get_guint8(tvb, offset + optoffset);
+ proto_tree_add_uint_format_value(field_tree, hf_ip_opt_ptr, tvb, offset + optoffset, 1, ptr, "%d%s",
+ ptr, ((ptr == 1) ? " (header is full)" :
+ (ptr < 5) ? " (points before first address)" :
+ (((ptr - 1) & 3) ? " (points to middle of field)" : "")));
+ optoffset++;
+ optlen--;
+ ptr--; /* ptr is 1-origin */
+
+ flg = tvb_get_guint8(tvb, offset + optoffset);
+ proto_tree_add_item(field_tree, hf_ip_opt_overflow, tvb, offset + optoffset, 1, ENC_NA);
+ flg &= 0xF;
+ proto_tree_add_item(field_tree, hf_ip_opt_flag, tvb, offset + optoffset, 1, ENC_NA);
+ optoffset++;
+ optlen--;
+
+ while (optlen > 0) {
+ if (flg == IPOPT_TS_TSANDADDR || flg == IPOPT_TS_PRESPEC) {
+ if (optlen < 8) {
+ proto_tree_add_expert(field_tree, pinfo, &ei_ip_subopt_too_long, tvb, offset + optoffset, optlen);
+ break;
+ }
+ addr = tvb_get_ipv4(tvb, offset + optoffset);
+ proto_tree_add_ipv4_format_value(field_tree, hf_ip_opt_time_stamp_addr, tvb, offset + optoffset, 4, addr,
+ "%s", ((addr == 0) ? "-" : get_hostname(addr)));
+ optoffset += 4;
+ optlen -= 4;
+
+ proto_tree_add_item(field_tree, hf_ip_opt_time_stamp, tvb, offset + optoffset, 4, ENC_BIG_ENDIAN);
+ optoffset += 4;
+ optlen -= 4;
+ } else {
+ if (optlen < 4) {
+ proto_tree_add_expert(field_tree, pinfo, &ei_ip_subopt_too_long, tvb, offset + optoffset, optlen);
+ break;
+ }
+ proto_tree_add_item(field_tree, hf_ip_opt_time_stamp, tvb, offset + optoffset, 4, ENC_BIG_ENDIAN);
+ optoffset += 4;
+ optlen -= 4;
+ }
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+/* Router Alert */
+static const range_string ra_rvals[] = {
+ {0, 0, "Router shall examine packet"},
+ {1, 65535, "Reserved"},
+ {0, 0, NULL}
+};
+
+static int
+dissect_ipopt_ra(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ /* Router-Alert, as defined by RFC2113 */
+ proto_tree *field_tree;
+ proto_item *tf;
+ guint32 value;
+
+ field_tree = ip_fixed_option_header(tree, pinfo, tvb, proto_ip_option_routeralert, ett_ip_option_ra, &tf, IPOLEN_RA, tvb_reported_length(tvb));
+
+ proto_tree_add_item_ret_uint(field_tree, hf_ip_opt_ra, tvb, 2, 2, ENC_BIG_ENDIAN, &value);
+ proto_item_append_text(tf, ": %s (%u)", rval_to_str(value, ra_rvals, "Unknown (%u)"), value);
+ return tvb_captured_length(tvb);
+}
+
+/* RFC 1770: Selective Directed Broadcast */
+static int
+dissect_ipopt_sdb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data _U_)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+ gint offset = 0,
+ optlen = tvb_reported_length(tvb);
+
+ field_tree = ip_var_option_header(tree, pinfo, tvb, proto_ip_option_sdb, ett_ip_option_sdb, &tf, optlen);
+
+ for (offset += 2, optlen -= 2; optlen >= 4; offset += 4, optlen -= 4)
+ proto_tree_add_item(field_tree, hf_ip_opt_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
+
+ if (optlen > 0)
+ proto_tree_add_item(field_tree, hf_ip_opt_padding, tvb, offset, optlen, ENC_NA);
+
+ return tvb_captured_length(tvb);
+}
+
+const value_string qs_func_vals[] = {
+ {QS_RATE_REQUEST, "Rate request"},
+ {QS_RATE_REPORT, "Rate report"},
+ {0, NULL}
+};
+
+static const value_string qs_rate_vals[] = {
+ { 0, "0 bit/s"},
+ { 1, "80 Kbit/s"},
+ { 2, "160 Kbit/s"},
+ { 3, "320 Kbit/s"},
+ { 4, "640 Kbit/s"},
+ { 5, "1.28 Mbit/s"},
+ { 6, "2.56 Mbit/s"},
+ { 7, "5.12 Mbit/s"},
+ { 8, "10.24 Mbit/s"},
+ { 9, "20.48 Mbit/s"},
+ {10, "40.96 Mbit/s"},
+ {11, "81.92 Mbit/s"},
+ {12, "163.84 Mbit/s"},
+ {13, "327.68 Mbit/s"},
+ {14, "655.36 Mbit/s"},
+ {15, "1.31072 Gbit/s"},
+ {0, NULL}
+};
+value_string_ext qs_rate_vals_ext = VALUE_STRING_EXT_INIT(qs_rate_vals);
+
+static int
+dissect_ipopt_qs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void * data)
+{
+ proto_tree *field_tree;
+ proto_item *tf;
+ proto_item *ti;
+ ws_ip4 *iph = (ws_ip4 *)data;
+ gint offset = 2;
+
+ guint8 command = tvb_get_guint8(tvb, offset);
+ guint8 function = command >> 4;
+ guint8 rate = command & QS_RATE_MASK;
+ guint8 ttl_diff;
+
+ field_tree = ip_fixed_option_header(tree, pinfo, tvb, proto_ip_option_qs, ett_ip_option_qs, &tf, IPOLEN_QS, tvb_reported_length(tvb));
+ proto_item_append_text(tf, ": %s (%u)", val_to_str(function, qs_func_vals, "Unknown (%u)"), function);
+
+ proto_tree_add_item(field_tree, hf_ip_opt_qs_func, tvb, offset, 1, ENC_NA);
+
+ if (function == QS_RATE_REQUEST) {
+ proto_tree_add_item(field_tree, hf_ip_opt_qs_rate, tvb, offset, 1, ENC_NA);
+ proto_tree_add_item(field_tree, hf_ip_opt_qs_ttl, tvb, offset + 1, 1, ENC_NA);
+ ttl_diff = (iph->ip_ttl - tvb_get_guint8(tvb, offset + 1) % 256);
+ ti = proto_tree_add_uint(field_tree, hf_ip_opt_qs_ttl_diff,
+ tvb, offset + 1, 1, ttl_diff);
+ proto_item_set_generated(ti);
+ proto_item_append_text(tf, ", %s, QS TTL %u, QS TTL diff %u",
+ val_to_str_ext(rate, &qs_rate_vals_ext, "Unknown (%u)"),
+ tvb_get_guint8(tvb, offset + 1), ttl_diff);
+ proto_tree_add_item(field_tree, hf_ip_opt_qs_nonce, tvb, offset + 2, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(field_tree, hf_ip_opt_qs_reserved, tvb, offset + 2, 4, ENC_BIG_ENDIAN);
+ } else if (function == QS_RATE_REPORT) {
+ proto_tree_add_item(field_tree, hf_ip_opt_qs_rate, tvb, offset, 1, ENC_NA);
+ proto_item_append_text(tf, ", %s",
+ val_to_str_ext(rate, &qs_rate_vals_ext, "Unknown (%u)"));
+ proto_tree_add_item(field_tree, hf_ip_opt_qs_unused, tvb, offset + 1, 1, ENC_NA);
+ proto_tree_add_item(field_tree, hf_ip_opt_qs_nonce, tvb, offset + 2, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item(field_tree, hf_ip_opt_qs_reserved, tvb, offset + 2, 4, ENC_BIG_ENDIAN);
+ }
+
+ return tvb_captured_length(tvb);
+}
+
+static void
+dissect_ip_options(tvbuff_t *tvb, int offset, guint length,
+ packet_info *pinfo, proto_tree *opt_tree,
+ proto_item *opt_item, void * data)
+{
+ guchar opt;
+ unsigned int optlen;
+ proto_tree *field_tree;
+ const char *name;
+ dissector_handle_t option_dissector;
+ guint nop_count = 0;
+ tvbuff_t *next_tvb;
+
+ while (length > 0) {
+ opt = tvb_get_guint8(tvb, offset);
+ --length; /* account for type byte */
+
+ if ((opt == IPOPT_EOOL) || (opt == IPOPT_NOP)) {
+ int local_proto;
+ proto_item* field_item;
+ /* We assume that the only options with no length are EOL and NOP options,
+ so that we can treat unknown options as having a minimum length of 2,
+ and at least be able to move on to the next option by using the length in the option. */
+
+ if (opt == IPOPT_EOOL)
+ {
+ local_proto = proto_ip_option_eol;
+ } else {
+ /* i.e. opt is IPOPT_NOP */
+ local_proto = proto_ip_option_nop;
+
+ if (opt_item && (nop_count == 0 || offset % 4)) {
+ /* Count number of NOP in a row within a uint32 */
+ nop_count++;
+
+ if (nop_count == 4) {
+ expert_add_info(pinfo, opt_item, &ei_ip_nop);
+ }
+ } else {
+ nop_count = 0;
+ }
+ }
+
+ field_item = proto_tree_add_item(opt_tree, local_proto, tvb, offset, 1, ENC_NA);
+ field_tree = proto_item_add_subtree(field_item, ett_ip_option_other);
+
+ dissect_ipopt_type(tvb, offset, field_tree);
+ offset++;
+
+ } else {
+ option_dissector = dissector_get_uint_handle(ip_option_table, opt);
+ if (option_dissector == NULL) {
+ name = wmem_strdup_printf(pinfo->pool, "Unknown (0x%02x)", opt);
+ } else {
+ name = dissector_handle_get_protocol_short_name(option_dissector);
+ }
+
+ /* Option has a length. Is it in the packet? */
+ if (length == 0) {
+ /* Bogus - packet must at least include option code byte and
+ length byte! */
+ proto_tree_add_expert_format(opt_tree, pinfo, &ei_ip_opt_len_invalid, tvb, offset, 1,
+ "%s (length byte past end of options)", name);
+ return;
+ }
+
+ optlen = tvb_get_guint8(tvb, offset + 1); /* total including type, len */
+ --length; /* account for length byte */
+
+ if (optlen < 2) {
+ /* Bogus - option length is too short to include option code and option length. */
+ proto_tree_add_expert_format(opt_tree, pinfo, &ei_ip_opt_len_invalid, tvb, offset, 2,
+ "%s (with too-short option length = %u byte%s)",
+ name, optlen, plurality(optlen, "", "s"));
+ return;
+ } else if (optlen - 2 > length) {
+ /* Bogus - option goes past the end of the header. */
+ proto_tree_add_expert_format(opt_tree, pinfo, &ei_ip_opt_len_invalid, tvb, offset, length,
+ "%s (option length = %u byte%s says option goes past end of options)",
+ name, optlen, plurality(optlen, "", "s"));
+ return;
+ }
+
+ if (option_dissector == NULL) {
+ proto_tree_add_subtree_format(opt_tree, tvb, offset, optlen, ett_ip_unknown_opt, NULL, "%s (%u byte%s)",
+ name, optlen, plurality(optlen, "", "s"));
+ } else {
+ next_tvb = tvb_new_subset_length(tvb, offset, optlen);
+ call_dissector_with_data(option_dissector, next_tvb, pinfo, opt_tree, data);
+ proto_item_append_text(proto_tree_get_parent(opt_tree), ", %s", name);
+ }
+
+ offset += optlen;
+ length -= (optlen-2); //already accounted for type and len bytes
+ }
+
+ if (opt == IPOPT_EOOL)
+ break;
+ }
+}
+
+/* This function searches the IP options for either a loose or strict source
+ * route option, then returns the offset to the destination address if the
+ * pointer is still valid or zero if the pointer is greater than the length.
+ *
+ * The guts of this function was taken from dissect_ip_tcp_options().
+ */
+static int
+get_dst_offset(tvbuff_t *tvb, int offset, guint length)
+{
+ guchar opt;
+ guint len;
+ int orig_offset = offset;
+
+ while (length > 0) {
+ opt = tvb_get_guint8(tvb, offset);
+ --length; /* account for type byte */
+
+ if ((opt != IPOPT_EOOL) && (opt != IPOPT_NOP)) {
+ /* Option has a length. Is it in the packet? */
+ if (length == 0) {
+ /* Bogus - packet must at least include option code byte and
+ length byte! */
+ return 0;
+ }
+ len = tvb_get_guint8(tvb, offset + 1); /* total including type, len */
+ --length; /* account for length byte */
+ if (len < 2) {
+ /* Bogus - option length is too short to include option code and
+ option length. */
+ return 0;
+ } else if (len - 2 > length) {
+ /* Bogus - option goes past the end of the header. */
+ return 0;
+ }
+
+ if (opt == IPOPT_SSR || opt == IPOPT_LSR) {
+ /* Hmm, what if you have both options? */
+ guint8 ptr;
+
+ ptr = tvb_get_guint8(tvb, offset + 2);
+ if (ptr < 4 || (ptr & 3) || (ptr > len)) {
+ return 0;
+ }
+ return (offset - orig_offset) + 4 + (len - 4);
+ }
+
+ offset += len;
+ length -= (len-2); /* subtract size of type and length */
+ } else {
+ offset += 1;
+ }
+ if (opt == IPOPT_EOOL)
+ return 0;
+ }
+
+ return 0;
+}
+
+/* Returns the valid ttl for the group address */
+static guint16
+local_network_control_block_addr_valid_ttl(guint32 addr)
+{
+ /* An exception list, as some protocols seem to insist on
+ * doing differently:
+ */
+
+ /* IETF's VRRP (rfc3768) */
+ if (IPLOCAL_NETWRK_CTRL_BLK_VRRP_ADDR == addr)
+ return IPLOCAL_NETWRK_CTRL_BLK_VRRP_TTL;
+ /* Cisco's GLPB */
+ if (IPLOCAL_NETWRK_CTRL_BLK_GLPB_ADDR == addr)
+ return IPLOCAL_NETWRK_CTRL_BLK_GLPB_TTL;
+ /* mDNS (draft-cheshire-dnsext-multicastdns-07) */
+ if (IPLOCAL_NETWRK_CTRL_BLK_MDNS_ADDR == addr)
+ return IPLOCAL_NETWRK_CTRL_BLK_MDNS_TTL;
+ /* LLMNR (rfc4795) */
+ if (IPLOCAL_NETWRK_CTRL_BLK_LLMNR_ADDR == addr)
+ return IPLOCAL_NETWRK_CTRL_BLK_ANY_TTL;
+ return IPLOCAL_NETWRK_CTRL_BLK_DEFAULT_TTL;
+}
+
+static const value_string dscp_short_vals[] = {
+ { IPDSFIELD_DSCP_DEFAULT, "CS0" },
+ { IPDSFIELD_DSCP_LE, "LE" },
+ { IPDSFIELD_DSCP_CS1, "CS1" },
+ { IPDSFIELD_DSCP_AF11, "AF11" },
+ { IPDSFIELD_DSCP_AF12, "AF12" },
+ { IPDSFIELD_DSCP_AF13, "AF13" },
+ { IPDSFIELD_DSCP_CS2, "CS2" },
+ { IPDSFIELD_DSCP_AF21, "AF21" },
+ { IPDSFIELD_DSCP_AF22, "AF22" },
+ { IPDSFIELD_DSCP_AF23, "AF23" },
+ { IPDSFIELD_DSCP_CS3, "CS3" },
+ { IPDSFIELD_DSCP_AF31, "AF31" },
+ { IPDSFIELD_DSCP_AF32, "AF32" },
+ { IPDSFIELD_DSCP_AF33, "AF33" },
+ { IPDSFIELD_DSCP_CS4, "CS4" },
+ { IPDSFIELD_DSCP_AF41, "AF41" },
+ { IPDSFIELD_DSCP_AF42, "AF42" },
+ { IPDSFIELD_DSCP_AF43, "AF43" },
+ { IPDSFIELD_DSCP_CS5, "CS5" },
+ { IPDSFIELD_VOICE_ADMIT, "VOICE-ADMIT" },
+ { IPDSFIELD_DSCP_EF, "EF PHB" },
+ { IPDSFIELD_DSCP_CS6, "CS6" },
+ { IPDSFIELD_DSCP_CS7, "CS7" },
+ { 0, NULL }};
+value_string_ext dscp_short_vals_ext = VALUE_STRING_EXT_INIT(dscp_short_vals);
+
+
+static const value_string dscp_vals[] = {
+ { IPDSFIELD_DSCP_DEFAULT, "Default" },
+ { IPDSFIELD_DSCP_LE, "Lower Effort" },
+ { IPDSFIELD_DSCP_CS1, "Class Selector 1" },
+ { IPDSFIELD_DSCP_AF11, "Assured Forwarding 11" },
+ { IPDSFIELD_DSCP_AF12, "Assured Forwarding 12" },
+ { IPDSFIELD_DSCP_AF13, "Assured Forwarding 13" },
+ { IPDSFIELD_DSCP_CS2, "Class Selector 2" },
+ { IPDSFIELD_DSCP_AF21, "Assured Forwarding 21" },
+ { IPDSFIELD_DSCP_AF22, "Assured Forwarding 22" },
+ { IPDSFIELD_DSCP_AF23, "Assured Forwarding 23" },
+ { IPDSFIELD_DSCP_CS3, "Class Selector 3" },
+ { IPDSFIELD_DSCP_AF31, "Assured Forwarding 31" },
+ { IPDSFIELD_DSCP_AF32, "Assured Forwarding 32" },
+ { IPDSFIELD_DSCP_AF33, "Assured Forwarding 33" },
+ { IPDSFIELD_DSCP_CS4, "Class Selector 4" },
+ { IPDSFIELD_DSCP_AF41, "Assured Forwarding 41" },
+ { IPDSFIELD_DSCP_AF42, "Assured Forwarding 42" },
+ { IPDSFIELD_DSCP_AF43, "Assured Forwarding 43" },
+ { IPDSFIELD_DSCP_CS5, "Class Selector 5" },
+ { IPDSFIELD_VOICE_ADMIT, "Voice Admit" },
+ { IPDSFIELD_DSCP_EF, "Expedited Forwarding" },
+ { IPDSFIELD_DSCP_CS6, "Class Selector 6" },
+ { IPDSFIELD_DSCP_CS7, "Class Selector 7" },
+ { 0, NULL }};
+value_string_ext dscp_vals_ext = VALUE_STRING_EXT_INIT(dscp_vals);
+
+static const value_string ecn_short_vals[] = {
+ { IPDSFIELD_ECT_NOT, "Not-ECT" },
+ { IPDSFIELD_ECT_1, "ECT(1)" },
+ { IPDSFIELD_ECT_0, "ECT(0)" },
+ { IPDSFIELD_CE, "CE" },
+ { 0, NULL }};
+value_string_ext ecn_short_vals_ext = VALUE_STRING_EXT_INIT(ecn_short_vals);
+
+static const value_string ecn_vals[] = {
+ { IPDSFIELD_ECT_NOT, "Not ECN-Capable Transport" },
+ { IPDSFIELD_ECT_1, "ECN-Capable Transport codepoint '01'" },
+ { IPDSFIELD_ECT_0, "ECN-Capable Transport codepoint '10'" },
+ { IPDSFIELD_CE, "Congestion Experienced" },
+ { 0, NULL }};
+value_string_ext ecn_vals_ext = VALUE_STRING_EXT_INIT(ecn_vals);
+
+static const value_string precedence_vals[] = {
+ { IPTOS_PREC_ROUTINE, "routine" },
+ { IPTOS_PREC_PRIORITY, "priority" },
+ { IPTOS_PREC_IMMEDIATE, "immediate" },
+ { IPTOS_PREC_FLASH, "flash" },
+ { IPTOS_PREC_FLASHOVERRIDE, "flash override" },
+ { IPTOS_PREC_CRITIC_ECP, "CRITIC/ECP" },
+ { IPTOS_PREC_INTERNETCONTROL, "internetwork control" },
+ { IPTOS_PREC_NETCONTROL, "network control" },
+ { 0, NULL }};
+
+static const value_string iptos_vals[] = {
+ { IPTOS_NONE, "None" },
+ { IPTOS_LOWCOST, "Minimize cost" },
+ { IPTOS_RELIABILITY, "Maximize reliability" },
+ { IPTOS_THROUGHPUT, "Maximize throughput" },
+ { IPTOS_LOWDELAY, "Minimize delay" },
+ { IPTOS_SECURITY, "Maximize security" },
+ { 0, NULL }
+};
+
+static const true_false_string flags_sf_set_evil = {
+ "Evil",
+ "Not evil"
+};
+
+gboolean
+ip_try_dissect(gboolean heur_first, guint nxt, tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, void *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, nxt, 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
+export_pdu(tvbuff_t *tvb, packet_info *pinfo)
+{
+ if (have_tap_listener(exported_pdu_tap)) {
+ exp_pdu_data_t *exp_pdu_data = wmem_new0(pinfo->pool, exp_pdu_data_t);
+
+ exp_pdu_data->tvb_captured_length = tvb_captured_length(tvb);
+ exp_pdu_data->tvb_reported_length = tvb_reported_length(tvb);
+ exp_pdu_data->pdu_tvb = tvb;
+ tap_queue_packet(exported_pdu_tap, pinfo, exp_pdu_data);
+ }
+}
+
+static int
+dissect_ip_v4(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_)
+{
+ proto_tree *ip_tree, *field_tree = NULL;
+ proto_item *ti, *tf;
+ guint32 addr;
+ int offset = 0, dst_off;
+ guint hlen, optlen;
+ guint16 ipsum;
+ fragment_head *ipfd_head = NULL;
+ tvbuff_t *next_tvb;
+ gboolean update_col_info = TRUE;
+ gboolean save_fragmented;
+ ws_ip4 *iph;
+ guint32 src32, dst32;
+ proto_tree *tree;
+ proto_item *item = NULL, *ttl_item;
+ guint16 ttl_valid;
+
+ tree = parent_tree;
+ iph = wmem_new0(pinfo->pool, ws_ip4);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPv4");
+ col_clear(pinfo->cinfo, COL_INFO);
+
+ iph->ip_ver = tvb_get_bits8(tvb, 0, 4);
+
+ hlen = tvb_get_bits8(tvb, 4, 4) * 4; /* IP header length, in bytes */
+
+ ti = proto_tree_add_item(tree, proto_ip, tvb, offset, hlen, ENC_NA);
+ ip_tree = proto_item_add_subtree(ti, ett_ip);
+
+ tf = proto_tree_add_bits_item(ip_tree, hf_ip_version, tvb, 0, 4, ENC_NA);
+ if (iph->ip_ver != 4) {
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "Bogus IPv4 version (%u, must be 4)", iph->ip_ver);
+ expert_add_info_format(pinfo, tf, &ei_ip_bogus_ip_version, "Bogus IPv4 version");
+ /* I have a Linux cooked capture with ethertype IPv4 containing an IPv6 packet, continnue dissection in that case*/
+ if (iph->ip_ver == 6) {
+ call_dissector(ipv6_handle, tvb, pinfo, tree);
+ }
+
+ return tvb_captured_length(tvb);
+ }
+
+ /* if IP is not referenced from any filters we don't need to worry about
+ generating any tree items. We must do this after we created the actual
+ protocol above so that proto hier stat still works though.
+ XXX: Note that because of the following optimization expert items must
+ not be generated inside of an 'if (tree) ...'
+ so that Analyze ! Expert ... will work.
+ */
+ if (!proto_field_is_referenced(parent_tree, proto_ip)) {
+ tree = NULL;
+ }
+
+ if (hlen < IPH_MIN_LEN) {
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "Bogus IP header length (%u, must be at least %u)",
+ hlen, IPH_MIN_LEN);
+ tf = proto_tree_add_uint_bits_format_value(ip_tree, hf_ip_hdr_len, tvb, (offset<<3)+4, 4, hlen,
+ ENC_BIG_ENDIAN, "%u bytes (%u)", hlen, hlen>>2);
+ expert_add_info_format(pinfo, tf, &ei_ip_bogus_header_length,
+ "Bogus IP header length (%u, must be at least %u)", hlen, IPH_MIN_LEN);
+ return tvb_captured_length(tvb);
+ }
+
+ // This should be consistent with tcp.hdr_len.
+ proto_tree_add_uint_bits_format_value(ip_tree, hf_ip_hdr_len, tvb, (offset<<3)+4, 4, hlen,
+ ENC_BIG_ENDIAN, "%u bytes (%u)", hlen, hlen>>2);
+
+ iph->ip_tos = tvb_get_guint8(tvb, offset + 1);
+ if (g_ip_dscp_actif) {
+ col_add_str(pinfo->cinfo, COL_DSCP_VALUE,
+ val_to_str_ext(IPDSFIELD_DSCP(iph->ip_tos), &dscp_short_vals_ext, "%u"));
+ }
+
+ if (tree) {
+ if (g_ip_dscp_actif) {
+ tf = proto_tree_add_item(ip_tree, hf_ip_dsfield, tvb, offset + 1, 1, ENC_NA);
+ proto_item_append_text(tf, " (DSCP: %s, ECN: %s)",
+ val_to_str_ext_const(IPDSFIELD_DSCP(iph->ip_tos), &dscp_short_vals_ext, "Unknown"),
+ val_to_str_ext_const(IPDSFIELD_ECN(iph->ip_tos), &ecn_short_vals_ext, "Unknown"));
+
+ field_tree = proto_item_add_subtree(tf, ett_ip_dsfield);
+ proto_tree_add_item(field_tree, hf_ip_dsfield_dscp, tvb, offset + 1, 1, ENC_NA);
+ proto_tree_add_item(field_tree, hf_ip_dsfield_ecn, tvb, offset + 1, 1, ENC_NA);
+ } else {
+ tf = proto_tree_add_uint_format_value(ip_tree, hf_ip_tos, tvb, offset + 1, 1,
+ iph->ip_tos,
+ "0x%02x (%s)",
+ iph->ip_tos,
+ val_to_str_const(IPTOS_TOS(iph->ip_tos),
+ iptos_vals, "Unknown"));
+
+ field_tree = proto_item_add_subtree(tf, ett_ip_tos);
+ proto_tree_add_item(field_tree, hf_ip_tos_precedence, tvb, offset + 1, 1, ENC_NA);
+ proto_tree_add_item(field_tree, hf_ip_tos_delay, tvb, offset + 1, 1, ENC_NA);
+ proto_tree_add_item(field_tree, hf_ip_tos_throughput, tvb, offset + 1, 1, ENC_NA);
+ proto_tree_add_item(field_tree, hf_ip_tos_reliability, tvb, offset + 1, 1, ENC_NA);
+ proto_tree_add_item(field_tree, hf_ip_tos_cost, tvb, offset + 1, 1, ENC_NA);
+ }
+ }
+
+ /* 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. */
+ iph->ip_len = tvb_get_ntohs(tvb, offset + 2);
+
+ if (iph->ip_len < hlen) {
+ if (ip_tso_supported && !iph->ip_len) {
+ /* TSO support enabled, and zero length. Assume the zero length is
+ * the result of TSO, and use the reported length instead. Note that
+ * we need to use the frame/reported length instead of the actually-
+ * available length, just in case a snaplen was used on capture. */
+ iph->ip_len = tvb_reported_length(tvb);
+ if (tree) {
+ tf = proto_tree_add_uint_format_value(ip_tree, hf_ip_len, tvb, offset + 2, 2,
+ iph->ip_len,
+ "%u bytes (reported as 0, presumed to be because of \"TCP segmentation offload\" (TSO))",
+ iph->ip_len);
+ proto_item_set_generated(tf);
+ }
+ } else {
+ /* TSO support not enabled, or non-zero length, so treat it as an error. */
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "Bogus IP length (%u, less than header length %u)",
+ iph->ip_len, hlen);
+ tf = proto_tree_add_uint_format_value(ip_tree, hf_ip_len, tvb, offset + 2, 2,
+ iph->ip_len,
+ "%u bytes (bogus, less than header length %u)",
+ iph->ip_len, hlen);
+ expert_add_info(pinfo, tf, &ei_ip_bogus_ip_length);
+ /* Can't dissect any further */
+ return tvb_captured_length(tvb);
+ }
+ } else {
+ tf = proto_tree_add_uint(ip_tree, hf_ip_len, tvb, offset + 2, 2, iph->ip_len);
+ if (iph->ip_len > tvb_reported_length(tvb)) {
+ /*
+ * Length runs past the data we're given.
+ * Note that if not in a ICMP error packet.
+ */
+ if (!pinfo->flags.in_error_pkt) {
+ expert_add_info_format(pinfo, tf, &ei_ip_bogus_ip_length,
+ "IPv4 total length exceeds packet length (%u bytes)",
+ tvb_reported_length(tvb));
+ }
+ } else {
+ /*
+ * Now that we know that the total length of this IP datagram isn't
+ * obviously bogus, adjust the length of this tvbuff to include only
+ * the IP datagram.
+ */
+ set_actual_length(tvb, iph->ip_len);
+ }
+ }
+
+ /* Only export after adjusting the length */
+ export_pdu(tvb, pinfo);
+
+ iph->ip_id = tvb_get_ntohs(tvb, offset + 4);
+ if (tree)
+ proto_tree_add_uint(ip_tree, hf_ip_id, tvb, offset + 4, 2, iph->ip_id);
+
+ iph->ip_off = tvb_get_ntohs(tvb, offset + 6);
+
+ if (ip_security_flag) {
+ /* RFC 3514 - The Security Flag in the IPv4 Header (April Fool's joke) */
+ static int * const ip_flags_evil[] = {
+ &hf_ip_flags_sf,
+ &hf_ip_flags_df,
+ &hf_ip_flags_mf,
+ NULL
+ };
+
+ tf = proto_tree_add_bitmask_with_flags(ip_tree, tvb, offset + 6, hf_ip_flags,
+ ett_ip_flags, ip_flags_evil, ENC_BIG_ENDIAN, BMT_NO_FALSE | BMT_NO_TFS | BMT_NO_INT);
+ if (iph->ip_off & IP_RF) {
+ expert_add_info(pinfo, tf, &ei_ip_evil_packet);
+ }
+ } else {
+ static int * const ip_flags[] = {
+ &hf_ip_flags_rf,
+ &hf_ip_flags_df,
+ &hf_ip_flags_mf,
+ NULL
+ };
+ tf = proto_tree_add_bitmask_with_flags(ip_tree, tvb, offset + 6, hf_ip_flags,
+ ett_ip_flags, ip_flags, ENC_BIG_ENDIAN, BMT_NO_FALSE | BMT_NO_TFS | BMT_NO_INT);
+ }
+
+ tf = proto_tree_add_uint_format_value(ip_tree, hf_ip_frag_offset, tvb, offset + 6, 2,
+ iph->ip_off, "%u", (iph->ip_off & IP_OFFSET) * 8);
+
+ iph->ip_ttl = tvb_get_guint8(tvb, offset + 8);
+ ttl_item = proto_tree_add_item(ip_tree, hf_ip_ttl, tvb, offset + 8, 1, ENC_BIG_ENDIAN);
+
+ iph->ip_proto = tvb_get_guint8(tvb, offset + 9);
+ if (tree) {
+ proto_tree_add_item(ip_tree, hf_ip_proto, tvb, offset + 9, 1, ENC_BIG_ENDIAN);
+ }
+
+ iph->ip_sum = tvb_get_ntohs(tvb, offset + 10);
+
+ /*
+ * If checksum checking is enabled, and we have the entire IP header
+ * available, check the checksum.
+ */
+ if (ip_check_checksum && tvb_bytes_exist(tvb, offset, hlen)) {
+ ipsum = ip_checksum_tvb(tvb, offset, hlen);
+ item = proto_tree_add_checksum(ip_tree, tvb, offset + 10, hf_ip_checksum, hf_ip_checksum_status, &ei_ip_checksum_bad, pinfo, ipsum,
+ ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY|PROTO_CHECKSUM_IN_CKSUM);
+ /*
+ * ip_checksum_tvb() should never return 0xFFFF here, because, to
+ * quote RFC 1624 section 3 "Discussion":
+ *
+ * In one's complement, there are two representations of
+ * zero: the all zero and the all one bit values, often
+ * referred to as +0 and -0. One's complement addition
+ * of non-zero inputs can produce -0 as a result, but
+ * never +0. Since there is guaranteed to be at least
+ * one non-zero field in the IP header, and the checksum
+ * field in the protocol header is the complement of the
+ * sum, the checksum field can never contain ~(+0), which
+ * is -0 (0xFFFF). It can, however, contain ~(-0), which
+ * is +0 (0x0000).
+ *
+ * ip_checksum_tvb() checksums the IPv4 header, where the "version"
+ * field is 4, ensuring that, in a valid IPv4 header, there is at
+ * least one non-zero field. We've already verified that the
+ * version is 4.
+ *
+ * ip_checksum_tvb() returns the negation of the one's-complement
+ * sum of all the data handed to it, and that data won't be
+ * all zero, so the sum won't be 0 (+0), and thus the negation
+ * won't be -0, i.e. won't be 0xFFFF.
+ */
+ if (ipsum == 0) {
+ /* XXX - Keeping hf_ip_checksum_calculated field for now. Doesn't fit into the
+ proto_tree_add_checksum design, but IP is a popular enough dissector that somebody
+ may have a legitimate reason for wanting it filtered */
+ item = proto_tree_add_uint(ip_tree, hf_ip_checksum_calculated, tvb,
+ offset + 10, 2, iph->ip_sum);
+ proto_item_set_generated(item);
+ } else {
+ proto_item_append_text(item, "(may be caused by \"IP checksum offload\"?)");
+
+ item = proto_tree_add_uint(ip_tree, hf_ip_checksum_calculated, tvb,
+ offset + 10, 2, in_cksum_shouldbe(iph->ip_sum, ipsum));
+ proto_item_set_generated(item);
+ }
+ } else {
+ ipsum = 0;
+ proto_tree_add_uint_format_value(ip_tree, hf_ip_checksum, tvb,
+ offset + 10, 2, iph->ip_sum,
+ "0x%04x [%s]",
+ iph->ip_sum,
+ ip_check_checksum ?
+ "not all data available" :
+ "validation disabled");
+ item = proto_tree_add_uint(ip_tree, hf_ip_checksum_status, tvb,
+ offset + 10, 0, PROTO_CHECKSUM_E_UNVERIFIED);
+ proto_item_set_generated(item);
+ }
+ src32 = tvb_get_ntohl(tvb, offset + IPH_SRC);
+ set_address_tvb(&pinfo->net_src, AT_IPv4, 4, tvb, offset + IPH_SRC);
+ 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", address_with_resolution_to_str(pinfo->pool, &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);
+ proto_item_set_hidden(item);
+ item = proto_tree_add_string(ip_tree, hf_ip_src_host, tvb, offset + 12, 4,
+ src_host);
+ proto_item_set_generated(item);
+ proto_item_set_hidden(item);
+ item = proto_tree_add_string(ip_tree, hf_ip_host, tvb, offset + 12, 4,
+ src_host);
+ proto_item_set_generated(item);
+ proto_item_set_hidden(item);
+ }
+
+ /* If there's an IP strict or loose source routing option, then the final
+ * L3 IP destination address will be the last entry in the routing header
+ * EXCEPT when the table is exhausted (pointer is greater than the length).
+ * In this case, the final L3 IP destination address is the one in the L3
+ * header. (REF: https://tools.ietf.org/html/rfc791#section-3.1)
+ */
+ if (hlen > IPH_MIN_LEN) {
+ /* There's more than just the fixed-length header. See if we've got
+ * either a strict or loose source route option and if so, return the
+ * offset into the tvb to where the real destination IP address is located.
+ */
+ dst_off = get_dst_offset(tvb, offset + 20, hlen - IPH_MIN_LEN);
+ }
+ else
+ dst_off = 0;
+
+ dst32 = tvb_get_ntohl(tvb, offset + IPH_DST + dst_off);
+ set_address_tvb(&pinfo->net_dst, AT_IPv4, 4, tvb, offset + IPH_DST + dst_off);
+ 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
+ * be expected to be 1. (see RFC 3171) Flag a TTL greater than 1.
+ *
+ * Flag a low TTL if the packet is not destined for a multicast address
+ * (e.g. 224.0.0.0/4) ... and the payload isn't protocol 103 (PIM).
+ * (see https://tools.ietf.org/html/rfc3973#section-4.7).
+ */
+ if (in4_addr_is_local_network_control_block(dst32)) {
+ if (iph->ip_proto == IP_PROTO_IGMP)
+ ttl_valid = IPLOCAL_NETWRK_CTRL_BLK_DEFAULT_TTL;
+ else
+ ttl_valid = local_network_control_block_addr_valid_ttl(dst32);
+ if (iph->ip_ttl != ttl_valid && ttl_valid != IPLOCAL_NETWRK_CTRL_BLK_ANY_TTL) {
+ expert_add_info_format(pinfo, ttl_item, &ei_ip_ttl_lncb, "\"Time To Live\" != %d for a packet sent to the "
+ "Local Network Control Block (see RFC 3171)",
+ ttl_valid);
+ }
+ } else if (iph->ip_ttl < 5 && !in4_addr_is_multicast(dst32) &&
+ /* At least BGP should appear here as well */
+ iph->ip_proto != IP_PROTO_PIM &&
+ iph->ip_proto != 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;
+
+ memcpy(&addr, iph->ip_dst.data, 4);
+ dst_host = get_hostname(addr);
+ if (ip_summary_in_tree) {
+ proto_item_append_text(ti, ", Dst: %s", address_with_resolution_to_str(pinfo->pool, &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(pinfo->pool, 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));
+ proto_item_set_generated(item);
+ proto_item_set_hidden(item);
+ }
+ else {
+ proto_tree_add_ipv4(ip_tree, hf_ip_dst, tvb, offset + 16, 4, addr);
+ item = proto_tree_add_ipv4(ip_tree, hf_ip_addr, tvb, offset + 16, 4,
+ addr);
+ proto_item_set_hidden(item);
+ item = proto_tree_add_string(ip_tree, hf_ip_dst_host, tvb, offset + 16,
+ 4, dst_host);
+ proto_item_set_generated(item);
+ proto_item_set_hidden(item);
+ item = proto_tree_add_string(ip_tree, hf_ip_host, tvb,
+ offset + 16 + dst_off, 4, dst_host);
+ proto_item_set_generated(item);
+ proto_item_set_hidden(item);
+ }
+
+ if (gbl_resolv_flags.maxmind_geoip) {
+ add_geoip_info(ip_tree, pinfo, tvb, offset, src32, dst32);
+ }
+ }
+
+ /* Decode IP options, if any. */
+ if (hlen > IPH_MIN_LEN) {
+ /* There's more than just the fixed-length header. Decode the options. */
+ optlen = hlen - IPH_MIN_LEN; /* length of options, in bytes */
+ field_tree = proto_tree_add_subtree_format(ip_tree, tvb, offset + 20, optlen,
+ ett_ip_options, &tf, "Options: (%u bytes)", optlen);
+ dissect_ip_options(tvb, offset + 20, optlen, pinfo, field_tree, tf, iph);
+ }
+
+ p_add_proto_data(pinfo->pool, pinfo, proto_ip, pinfo->curr_layer_num, GUINT_TO_POINTER((guint)iph->ip_proto));
+ tap_queue_packet(ip_tap, pinfo, iph);
+
+ /* Skip over header + options */
+ offset += hlen;
+
+ /* 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)) &&
+ iph->ip_len > hlen &&
+ tvb_bytes_exist(tvb, offset, iph->ip_len - hlen) &&
+ ipsum == 0) {
+ guint32 frag_id;
+ frag_id = iph->ip_proto ^ iph->ip_id ^ src32 ^ dst32;
+ /* XXX: Should there be a way to force the VLAN ID not to
+ * be taken into account for reassembly even with non publicly
+ * routable IP addresses?
+ */
+ if (in4_addr_is_private(dst32) || in4_addr_is_private(src32) ||
+ in4_addr_is_link_local(dst32) || in4_addr_is_link_local(src32) ||
+ prefs.strict_conversation_tracking_heuristics) {
+ frag_id ^= pinfo->vlan_id;
+ }
+ ipfd_head = fragment_add_check(&ip_reassembly_table, tvb, offset,
+ pinfo,
+ frag_id,
+ NULL,
+ (iph->ip_off & IP_OFFSET) * 8,
+ iph->ip_len - hlen,
+ iph->ip_off & IP_MF);
+
+ next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled IPv4",
+ ipfd_head, &ip_frag_items,
+ &update_col_info, ip_tree);
+ } else {
+ /* If this is the first fragment, dissect its contents, otherwise
+ just show it as a fragment.
+
+ 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) {
+ /* Not the first fragment - don't dissect it. */
+ next_tvb = NULL;
+ } else {
+ /* First fragment, or not fragmented. Dissect what we have here. */
+
+ /* Get a tvbuff for the payload. */
+ next_tvb = tvb_new_subset_remaining(tvb, offset);
+
+ /*
+ * If this is the first fragment, but not the only fragment,
+ * tell the next protocol that.
+ */
+ if (iph->ip_off & IP_MF)
+ pinfo->fragmented = TRUE;
+ else
+ pinfo->fragmented = FALSE;
+ }
+ }
+
+ if (next_tvb == NULL) {
+ /* Just show this as a fragment. */
+ col_add_fstr(pinfo->cinfo, COL_INFO,
+ "Fragmented IP protocol (proto=%s %u, off=%u, ID=%04x)",
+ ipprotostr(iph->ip_proto), iph->ip_proto,
+ (iph->ip_off & IP_OFFSET) * 8, iph->ip_id);
+ if ( ipfd_head && ipfd_head->reassembled_in != pinfo->num ) {
+ col_append_frame_number(pinfo, COL_INFO, " [Reassembled in #%u]",
+ ipfd_head->reassembled_in);
+ }
+
+ call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo,
+ parent_tree);
+ pinfo->fragmented = save_fragmented;
+ return tvb_captured_length(tvb);
+ }
+
+ if (tvb_reported_length(next_tvb) > 0) {
+ /* Hand off to the next protocol.
+
+ XXX - setting the columns only after trying various dissectors means
+ that if one of those dissectors throws an exception, the frame won't
+ 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 (!ip_try_dissect(try_heuristic_first, iph->ip_proto, next_tvb, pinfo,
+ parent_tree, iph)) {
+ /* Unknown protocol */
+ if (update_col_info) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s (%u)",
+ ipprotostr(iph->ip_proto), iph->ip_proto);
+ }
+ call_data_dissector(next_tvb, pinfo, parent_tree);
+ }
+ }
+ pinfo->fragmented = save_fragmented;
+ return tvb_captured_length(tvb);
+}
+
+static int
+dissect_ip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
+{
+ proto_tree *ip_tree;
+ proto_item *ti, *tf;
+ guint8 version;
+
+ version = tvb_get_guint8(tvb, 0) >> 4;
+
+ if(version == 4){
+ return dissect_ip_v4(tvb, pinfo, tree, data);
+ }
+ if(version == 6){
+ return call_dissector(ipv6_handle, tvb, pinfo, tree);
+ }
+
+ /* 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_bits_item(ip_tree, hf_ip_version, tvb, 0, 4, ENC_NA);
+ expert_add_info(pinfo, tf, &ei_ip_bogus_ip_version);
+ return 1;
+}
+
+static gboolean
+dissect_ip_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
+{
+ int length, tot_length;
+ guint8 oct, version, ihl;
+
+/*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |Version| IHL |Type of Service| Total Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+*/
+ length = tvb_captured_length(tvb);
+ if(length<4){
+ /* Need at least 4 bytes to make some sort of decision */
+ return FALSE;
+ }
+ oct = tvb_get_guint8(tvb,0);
+ ihl = oct & 0x0f;
+ version = oct >> 4;
+ if(version == 6){
+/*
+ 3. IPv6 Header Format
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |Version| Traffic Class | Flow Label |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Payload Length | Next Header | Hop Limit |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Source Address +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ + +
+ | |
+ + Destination Address +
+ | |
+ + +
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Version 4-bit Internet Protocol version number = 6.
+
+ Traffic Class 8-bit traffic class field. See section 7.
+
+ Flow Label 20-bit flow label. See section 6.
+
+ Payload Length 16-bit unsigned integer. Length of the IPv6
+ payload, i.e., the rest of the packet following
+ this IPv6 header, in octets. (Note that any
+ extension headers [section 4] present are
+ considered part of the payload, i.e., included
+ in the length count.)
+
+
+*/
+ if(length<8){
+ /* Need at least 8 bytes to make a decision */
+ return FALSE;
+ }
+ tot_length = tvb_get_ntohs(tvb,4);
+ if((tot_length + 40) != (int)tvb_reported_length(tvb)){
+ return FALSE;
+ }
+ call_dissector(ipv6_handle, tvb, pinfo, tree);
+ return TRUE;
+ }
+ /* version == IPv4 , the minimum value for a correct header is 5 */
+ if((version != 4)|| (ihl < 5)){
+ return FALSE;
+ }
+ /* Total Length is the length of the datagram, measured in octets,
+ * including internet header and data.
+ */
+ tot_length = tvb_get_ntohs(tvb,2);
+
+ if(tot_length != (int)tvb_reported_length(tvb)){
+ return FALSE;
+ }
+
+ dissect_ip_v4(tvb, pinfo, tree, data);
+ return TRUE;
+}
+
+void
+proto_register_ip(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_ip_version,
+ { "Version", "ip.version", FT_UINT8, BASE_DEC,
+ NULL, 0x00, NULL, HFILL }},
+
+ // "IHL" in https://tools.ietf.org/html/rfc791#section-3.1 and
+ // https://en.wikipedia.org/wiki/IPv4#Header
+ { &hf_ip_hdr_len,
+ { "Header Length", "ip.hdr_len", FT_UINT8, BASE_DEC,
+ NULL, 0x0, "Header length in 32-bit words", HFILL }},
+
+ { &hf_ip_dsfield,
+ { "Differentiated Services Field", "ip.dsfield", FT_UINT8, BASE_HEX,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_dsfield_dscp,
+ { "Differentiated Services Codepoint", "ip.dsfield.dscp", FT_UINT8, BASE_DEC | BASE_EXT_STRING,
+ &dscp_vals_ext, IPDSFIELD_DSCP_MASK, NULL, HFILL }},
+
+ { &hf_ip_dsfield_ecn,
+ { "Explicit Congestion Notification", "ip.dsfield.ecn", FT_UINT8, BASE_DEC | BASE_EXT_STRING,
+ &ecn_vals_ext, IPDSFIELD_ECN_MASK, NULL, HFILL }},
+
+ { &hf_ip_tos,
+ { "Type of Service", "ip.tos", FT_UINT8, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_tos_precedence,
+ { "Precedence", "ip.tos.precedence", FT_UINT8, BASE_DEC,
+ VALS(precedence_vals), IPTOS_PREC_MASK, NULL, HFILL }},
+
+ { &hf_ip_tos_delay,
+ { "Delay", "ip.tos.delay", FT_BOOLEAN, 8,
+ TFS(&tfs_low_normal), IPTOS_LOWDELAY, NULL, HFILL }},
+
+ { &hf_ip_tos_throughput,
+ { "Throughput", "ip.tos.throughput", FT_BOOLEAN, 8,
+ TFS(&tfs_high_normal), IPTOS_THROUGHPUT, NULL, HFILL }},
+
+ { &hf_ip_tos_reliability,
+ { "Reliability", "ip.tos.reliability", FT_BOOLEAN, 8,
+ TFS(&tfs_high_normal), IPTOS_RELIABILITY, NULL, HFILL }},
+
+ { &hf_ip_tos_cost,
+ { "Cost", "ip.tos.cost", FT_BOOLEAN, 8,
+ TFS(&tfs_low_normal), IPTOS_LOWCOST, NULL, HFILL }},
+
+ { &hf_ip_len,
+ { "Total Length", "ip.len", FT_UINT16, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_id,
+ { "Identification", "ip.id", FT_UINT16, BASE_HEX_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_dst,
+ { "Destination Address", "ip.dst", FT_IPv4, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_dst_host,
+ { "Destination Host", "ip.dst_host", FT_STRING, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_src,
+ { "Source Address", "ip.src", FT_IPv4, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_src_host,
+ { "Source Host", "ip.src_host", FT_STRING, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_addr,
+ { "Source or Destination Address", "ip.addr", FT_IPv4, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_host,
+ { "Source or Destination Host", "ip.host", FT_STRING, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_geoip_country,
+ { "Source or Destination GeoIP Country", "ip.geoip.country",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_country_iso,
+ { "Source or Destination GeoIP ISO Two Letter Country Code", "ip.geoip.country_iso",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_city,
+ { "Source or Destination GeoIP City", "ip.geoip.city",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_as_number,
+ { "Source or Destination GeoIP AS Number", "ip.geoip.asnum",
+ FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_as_org,
+ { "Source or Destination GeoIP AS Organization", "ip.geoip.org",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_latitude,
+ { "Source or Destination GeoIP Latitude", "ip.geoip.lat",
+ FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_longitude,
+ { "Source or Destination GeoIP Longitude", "ip.geoip.lon",
+ FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_src_summary,
+ { "Source GeoIP", "ip.geoip.src_summary",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_src_country,
+ { "Source GeoIP Country", "ip.geoip.src_country",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_src_country_iso,
+ { "Source GeoIP ISO Two Letter Country Code", "ip.geoip.src_country_iso",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_src_city,
+ { "Source GeoIP City", "ip.geoip.src_city",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_src_as_number,
+ { "Source GeoIP AS Number", "ip.geoip.src_asnum",
+ FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_src_as_org,
+ { "Source GeoIP AS Organization", "ip.geoip.src_org",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_src_latitude,
+ { "Source GeoIP Latitude", "ip.geoip.src_lat",
+ FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_src_longitude,
+ { "Source GeoIP Longitude", "ip.geoip.src_lon",
+ FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_dst_summary,
+ { "Destination GeoIP", "ip.geoip.dst_summary",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_dst_country,
+ { "Destination GeoIP Country", "ip.geoip.dst_country",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_dst_country_iso,
+ { "Destination GeoIP ISO Two Letter Country Code", "ip.geoip.dst_country_iso",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_dst_city,
+ { "Destination GeoIP City", "ip.geoip.dst_city",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_dst_as_number,
+ { "Destination GeoIP AS Number", "ip.geoip.dst_asnum",
+ FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_dst_as_org,
+ { "Destination GeoIP AS Organization", "ip.geoip.dst_org",
+ FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_dst_latitude,
+ { "Destination GeoIP Latitude", "ip.geoip.dst_lat",
+ FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_geoip_dst_longitude,
+ { "Destination GeoIP Longitude", "ip.geoip.dst_lon",
+ FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_flags,
+ { "Flags", "ip.flags", FT_UINT8, BASE_HEX,
+ NULL, 0xE0, "Flags (3 bits)", HFILL }},
+
+ { &hf_ip_flags_sf,
+ { "Security flag", "ip.flags.sf", FT_BOOLEAN, 8,
+ TFS(&flags_sf_set_evil), 0x80, "Security flag (RFC 3514)", HFILL }},
+
+ { &hf_ip_flags_rf,
+ { "Reserved bit", "ip.flags.rb", FT_BOOLEAN, 8,
+ TFS(&tfs_set_notset), 0x80, NULL, HFILL }},
+
+ { &hf_ip_flags_df,
+ { "Don't fragment", "ip.flags.df", FT_BOOLEAN, 8,
+ TFS(&tfs_set_notset), 0x40, NULL, HFILL }},
+
+ { &hf_ip_flags_mf,
+ { "More fragments", "ip.flags.mf", FT_BOOLEAN, 8,
+ TFS(&tfs_set_notset), 0x20, NULL, HFILL }},
+
+ { &hf_ip_frag_offset,
+ { "Fragment Offset", "ip.frag_offset", FT_UINT16, BASE_DEC,
+ NULL, IP_OFFSET, "Fragment offset (13 bits)", HFILL }},
+
+ { &hf_ip_ttl,
+ { "Time to Live", "ip.ttl", FT_UINT8, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_proto,
+ { "Protocol", "ip.proto", FT_UINT8, BASE_DEC | BASE_EXT_STRING,
+ &ipproto_val_ext, 0x0, NULL, HFILL }},
+
+ { &hf_ip_checksum,
+ { "Header Checksum", "ip.checksum", FT_UINT16, BASE_HEX,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_checksum_calculated,
+ { "Calculated Checksum", "ip.checksum_calculated", FT_UINT16, BASE_HEX, NULL, 0x0,
+ "The expected IP checksum field as calculated from the IP datagram", HFILL }},
+
+ { &hf_ip_checksum_status,
+ { "Header checksum status", "ip.checksum.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
+ NULL, HFILL }},
+
+ /* IP options related fields */
+ { &hf_ip_opt_type,
+ { "Type", "ip.opt.type", FT_UINT8, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_type_copy,
+ { "Copy on fragmentation", "ip.opt.type.copy", FT_BOOLEAN, 8,
+ TFS(&tfs_yes_no), IPOPT_COPY_MASK, NULL, HFILL }},
+
+ { &hf_ip_opt_type_class,
+ { "Class", "ip.opt.type.class", FT_UINT8, BASE_DEC,
+ VALS(ipopt_type_class_vals), IPOPT_CLASS_MASK, NULL, HFILL }},
+
+ { &hf_ip_opt_type_number,
+ { "Number", "ip.opt.type.number", FT_UINT8, BASE_DEC,
+ VALS(ipopt_type_number_vals), IPOPT_NUMBER_MASK, NULL, HFILL }},
+
+ { &hf_ip_opt_len,
+ { "Length", "ip.opt.len", FT_UINT8, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_ptr,
+ { "Pointer", "ip.opt.ptr", FT_UINT8, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_sid,
+ { "Stream Identifier", "ip.opt.sid", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "SATNET stream identifier", HFILL }},
+
+ { &hf_ip_opt_mtu,
+ { "MTU", "ip.opt.mtu", FT_UINT16, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_id_number,
+ { "ID Number", "ip.opt.id_number", FT_UINT16, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_ohc,
+ { "Outbound Hop Count", "ip.opt.ohc", FT_UINT16, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_rhc,
+ { "Return Hop Count", "ip.opt.rhc", FT_UINT16, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_originator,
+ { "Originator IP Address", "ip.opt.originator", FT_IPv4, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_ra,
+ { "Router Alert", "ip.opt.ra", FT_UINT16, BASE_DEC | BASE_RANGE_STRING,
+ RVALS(ra_rvals), 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_addr,
+ { "IP Address", "ip.opt.addr", FT_IPv4, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_padding,
+ { "Padding", "ip.opt.padding", FT_BYTES, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_qs_func,
+ { "Function", "ip.opt.qs_func", FT_UINT8, BASE_DEC,
+ VALS(qs_func_vals), QS_FUNC_MASK, NULL, HFILL }},
+
+ { &hf_ip_opt_qs_rate,
+ { "Rate", "ip.opt.qs_rate", FT_UINT8, BASE_DEC | BASE_EXT_STRING,
+ &qs_rate_vals_ext, QS_RATE_MASK, NULL, HFILL }},
+
+ { &hf_ip_opt_qs_ttl,
+ { "QS TTL", "ip.opt.qs_ttl", FT_UINT8, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_qs_ttl_diff,
+ { "TTL Diff", "ip.opt.qs_ttl_diff", FT_UINT8, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_qs_unused,
+ { "Not Used", "ip.opt.qs_unused", FT_UINT8, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_qs_nonce,
+ { "QS Nonce", "ip.opt.qs_nonce", FT_UINT32, BASE_HEX,
+ NULL, 0xFFFFFFFC, NULL, HFILL }},
+
+ { &hf_ip_opt_qs_reserved,
+ { "Reserved", "ip.opt.qs_reserved", FT_UINT32, BASE_HEX,
+ NULL, 0x00000003, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_rfc791_sec,
+ { "Security", "ip.opt.sec_rfc791_sec", FT_UINT16, BASE_HEX,
+ VALS(secl_rfc791_vals), 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_rfc791_comp,
+ { "Compartments", "ip.opt.sec_rfc791_comp", FT_UINT16, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_rfc791_hr,
+ { "Handling Restrictions", "ip.opt.sec_rfc791_hr", FT_STRING, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_rfc791_tcc,
+ { "Transmission Control Code", "ip.opt.sec_rfc791_tcc", FT_STRING, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_cl,
+ { "Classification Level", "ip.opt.sec_cl", FT_UINT8, BASE_HEX,
+ VALS(sec_cl_vals), 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_prot_auth_flags,
+ { "Protection Authority Flags", "ip.opt.sec_prot_auth_flags", FT_UINT8, BASE_HEX,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_prot_auth_genser,
+ { "GENSER", "ip.opt.sec_prot_auth_genser", FT_BOOLEAN, 8,
+ TFS(&ip_opt_sec_prot_auth_flag_tfs), 0x80, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_prot_auth_siop_esi,
+ { "SIOP-ESI", "ip.opt.sec_prot_auth_siop_esi", FT_BOOLEAN, 8,
+ TFS(&ip_opt_sec_prot_auth_flag_tfs), 0x40, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_prot_auth_sci,
+ { "SCI", "ip.opt.sec_prot_auth_sci", FT_BOOLEAN, 8,
+ TFS(&ip_opt_sec_prot_auth_flag_tfs), 0x20, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_prot_auth_nsa,
+ { "NSA", "ip.opt.sec_prot_auth_nsa", FT_BOOLEAN, 8,
+ TFS(&ip_opt_sec_prot_auth_flag_tfs), 0x10, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_prot_auth_doe,
+ { "DOE", "ip.opt.sec_prot_auth_doe", FT_BOOLEAN, 8,
+ TFS(&ip_opt_sec_prot_auth_flag_tfs), 0x08, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_prot_auth_unassigned,
+ { "Unassigned", "ip.opt.sec_prot_auth_unassigned", FT_UINT8, BASE_HEX,
+ NULL, 0x06, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_prot_auth_unassigned2,
+ { "Unassigned", "ip.opt.sec_prot_auth_unassigned", FT_UINT8, BASE_HEX,
+ NULL, 0xFE, NULL, HFILL }},
+
+ { &hf_ip_opt_sec_prot_auth_fti,
+ { "Field Termination Indicator", "ip.opt.sec_prot_auth_fti", FT_BOOLEAN, 8,
+ TFS(&ip_opt_sec_prot_auth_fti_tfs), 0x01, NULL, HFILL }},
+
+ { &hf_ip_opt_ext_sec_add_sec_info_format_code,
+ { "Additional Security Info Format Code", "ip.opt.ext_sec_add_sec_info_format_code", FT_UINT8, BASE_HEX,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_opt_ext_sec_add_sec_info,
+ { "Additional Security Info", "ip.opt.ext_sec_add_sec_info", FT_BYTES, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_rec_rt,
+ { "Recorded Route", "ip.rec_rt", FT_IPv4, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_ip_rec_rt_host,
+ { "Recorded Route Host", "ip.rec_rt_host", FT_STRING, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_cur_rt,
+ { "Current Route", "ip.cur_rt", FT_IPv4, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_ip_cur_rt_host,
+ { "Current Route Host", "ip.cur_rt_host", FT_STRING, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_src_rt,
+ { "Source Route", "ip.src_rt", FT_IPv4, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_ip_src_rt_host,
+ { "Source Route Host", "ip.src_rt_host", FT_STRING, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_empty_rt,
+ { "Empty Route", "ip.empty_rt", FT_IPv4, BASE_NONE, NULL, 0x0,
+ NULL, HFILL }},
+
+ { &hf_ip_empty_rt_host,
+ { "Empty Route Host", "ip.empty_rt_host", FT_STRING, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_cipso_tag_type,
+ { "Tag Type", "ip.cipso.tag_type", FT_UINT8, BASE_DEC,
+ VALS(cipso_tag_type_vals), 0x0, NULL, HFILL }},
+
+
+ { &hf_ip_fragment_overlap,
+ { "Fragment overlap", "ip.fragment.overlap", FT_BOOLEAN, BASE_NONE,
+ NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
+
+ { &hf_ip_fragment_overlap_conflict,
+ { "Conflicting data in fragment overlap", "ip.fragment.overlap.conflict",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Overlapping fragments contained conflicting data", HFILL }},
+
+ { &hf_ip_fragment_multiple_tails,
+ { "Multiple tail fragments found", "ip.fragment.multipletails",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Several tails were found when defragmenting the packet", HFILL }},
+
+ { &hf_ip_fragment_too_long_fragment,
+ { "Fragment too long", "ip.fragment.toolongfragment",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Fragment contained data past end of packet", HFILL }},
+
+ { &hf_ip_fragment_error,
+ { "Defragmentation error", "ip.fragment.error", FT_FRAMENUM, BASE_NONE,
+ NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL }},
+
+ { &hf_ip_fragment_count,
+ { "Fragment count", "ip.fragment.count", FT_UINT32, BASE_DEC,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_fragment,
+ { "IPv4 Fragment", "ip.fragment", FT_FRAMENUM, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_fragments,
+ { "IPv4 Fragments", "ip.fragments", FT_BYTES, BASE_NONE,
+ NULL, 0x0, NULL, HFILL }},
+
+ { &hf_ip_reassembled_in,
+ { "Reassembled IPv4 in frame", "ip.reassembled_in", FT_FRAMENUM, BASE_NONE,
+ NULL, 0x0, "This IPv4 packet is reassembled in this frame", HFILL }},
+
+ { &hf_ip_reassembled_length,
+ { "Reassembled IPv4 length", "ip.reassembled.length", FT_UINT32, BASE_DEC,
+ NULL, 0x0, "The total length of the reassembled payload", HFILL }},
+
+ { &hf_ip_reassembled_data,
+ { "Reassembled IPv4 data", "ip.reassembled.data", FT_BYTES, BASE_NONE,
+ NULL, 0x0, "The reassembled payload", HFILL }},
+
+ /* Generated from convert_proto_tree_add_text.pl */
+ { &hf_ip_cipso_doi, { "DOI", "ip.cipso.doi", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_ip_cipso_sensitivity_level, { "Sensitivity Level", "ip.cipso.sensitivity_level", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_ip_cipso_categories, { "Categories", "ip.cipso.categories", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_ip_cipso_tag_data, { "Tag data", "ip.cipso.tag_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+ { &hf_ip_opt_overflow, { "Overflow", "ip.opt.overflow", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }},
+ { &hf_ip_opt_flag, { "Flag", "ip.opt.flag", FT_UINT8, BASE_HEX, VALS(ipopt_timestamp_flag_vals), 0x0F, NULL, HFILL }},
+ { &hf_ip_opt_time_stamp, { "Time stamp", "ip.opt.time_stamp", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
+ { &hf_ip_opt_time_stamp_addr, { "Address", "ip.opt.time_stamp_addr", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
+
+};
+
+ static gint *ett[] = {
+ &ett_ip,
+ &ett_ip_dsfield,
+ &ett_ip_tos,
+ &ett_ip_flags,
+ &ett_ip_options,
+ &ett_ip_option_eool,
+ &ett_ip_option_nop,
+ &ett_ip_option_sec,
+ &ett_ip_option_route,
+ &ett_ip_option_timestamp,
+ &ett_ip_option_ext_security,
+ &ett_ip_option_cipso,
+ &ett_ip_option_sid,
+ &ett_ip_option_mtu,
+ &ett_ip_option_tr,
+ &ett_ip_option_ra,
+ &ett_ip_option_sdb,
+ &ett_ip_option_qs,
+ &ett_ip_option_other,
+ &ett_ip_fragments,
+ &ett_ip_fragment,
+ &ett_ip_opt_type,
+ &ett_ip_opt_sec_prot_auth_flags,
+ &ett_ip_unknown_opt,
+ &ett_geoip_info
+ };
+ static ei_register_info ei[] = {
+ { &ei_ip_opt_len_invalid, { "ip.opt.len.invalid", PI_PROTOCOL, PI_WARN, "Invalid length for option", EXPFILL }},
+ { &ei_ip_opt_sec_prot_auth_fti, { "ip.opt.len.invalid", PI_PROTOCOL, PI_WARN, "Field Termination Indicator set to 1 for last byte of option", EXPFILL }},
+ { &ei_ip_extraneous_data, { "ip.opt.len.invalid", PI_PROTOCOL, PI_WARN, "Extraneous data in option", EXPFILL }},
+ { &ei_ip_opt_ptr_before_address, { "ip.opt.ptr.before_address", PI_PROTOCOL, PI_WARN, "Pointer points before first address", EXPFILL }},
+ { &ei_ip_opt_ptr_middle_address, { "ip.opt.ptr.middle_address", PI_PROTOCOL, PI_WARN, "Pointer points to middle of address", EXPFILL }},
+ { &ei_ip_subopt_too_long, { "ip.subopt_too_long", PI_PROTOCOL, PI_WARN, "Suboption would go past end of option", EXPFILL }},
+ { &ei_ip_nop, { "ip.nop", PI_PROTOCOL, PI_WARN, "4 NOP in a row - a router may have removed some options", EXPFILL }},
+ { &ei_ip_bogus_ip_length, { "ip.bogus_ip_length", PI_PROTOCOL, PI_ERROR, "Bogus IP length", EXPFILL }},
+ { &ei_ip_evil_packet, { "ip.evil_packet", PI_PROTOCOL, PI_WARN, "Packet has evil intent", EXPFILL }},
+ { &ei_ip_checksum_bad, { "ip.checksum_bad.expert", PI_CHECKSUM, PI_ERROR, "Bad checksum", EXPFILL }},
+ { &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 }},
+ { &ei_ip_bogus_header_length, { "ip.bogus_header_length", PI_PROTOCOL, PI_ERROR, "Bogus IP header length", EXPFILL }},
+ };
+
+ /* Decode As handling */
+ static build_valid_func ip_da_build_value[1] = {ip_value};
+ static decode_as_value_t ip_da_values = {ip_prompt, 1, ip_da_build_value};
+ static decode_as_t ip_da = {"ip", "ip.proto", 1, 0, &ip_da_values, NULL, NULL,
+ decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
+
+ module_t *ip_module;
+ expert_module_t* expert_ip;
+
+ proto_ip = proto_register_protocol("Internet Protocol Version 4", "IPv4", "ip");
+ proto_register_field_array(proto_ip, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ expert_ip = expert_register_protocol(proto_ip);
+ expert_register_field_array(expert_ip, ei, array_length(ei));
+
+ /* subdissector code */
+ ip_dissector_table = register_dissector_table("ip.proto", "IP protocol",
+ proto_ip, FT_UINT8, BASE_DEC);
+ ip_option_table = register_dissector_table("ip.option", "IP Options",
+ proto_ip, FT_UINT8, BASE_DEC);
+ heur_subdissector_list = register_heur_dissector_list("ip", proto_ip);
+ register_capture_dissector_table("ip.proto", "IP protocol");
+
+ /* Register configuration options */
+ ip_module = prefs_register_protocol(proto_ip, NULL);
+ prefs_register_bool_preference(ip_module, "decode_tos_as_diffserv",
+ "Decode IPv4 TOS field as DiffServ field",
+ "Whether the IPv4 type-of-service field should be decoded as a "
+ "Differentiated Services field (see RFC2474/RFC2475)", &g_ip_dscp_actif);
+ prefs_register_bool_preference(ip_module, "defragment",
+ "Reassemble fragmented IPv4 datagrams",
+ "Whether fragmented IPv4 datagrams should be reassembled", &ip_defragment);
+ prefs_register_bool_preference(ip_module, "summary_in_tree",
+ "Show IPv4 summary in protocol tree",
+ "Whether the IPv4 summary line should be shown in the protocol tree",
+ &ip_summary_in_tree);
+ prefs_register_bool_preference(ip_module, "check_checksum",
+ "Validate the IPv4 checksum if possible",
+ "Whether to validate the IPv4 checksum", &ip_check_checksum);
+ prefs_register_bool_preference(ip_module, "tso_support",
+ "Support packet-capture from IP TSO-enabled hardware",
+ "Whether to correct for TSO-enabled (TCP segmentation offload) hardware "
+ "captures, such as spoofing the IP packet length", &ip_tso_supported);
+
+ prefs_register_obsolete_preference(ip_module, "use_geoip");
+ prefs_register_bool_preference(ip_module, "security_flag" ,
+ "Interpret Reserved flag as Security flag (RFC 3514)",
+ "Whether to interpret the originally reserved flag as security flag",
+ &ip_security_flag);
+ prefs_register_bool_preference(ip_module, "try_heuristic_first",
+ "Try heuristic sub-dissectors first",
+ "Try to decode a packet using an heuristic sub-dissector before using a sub-dissector registered to a specific port",
+ &try_heuristic_first);
+
+ prefs_register_static_text_preference(ip_module, "text_use_geoip",
+ "IP geolocation settings can be changed in the Name Resolution preferences",
+ "IP geolocation settings can be changed in the Name Resolution preferences");
+
+ ip_handle = register_dissector("ip", dissect_ip, proto_ip);
+ reassembly_table_register(&ip_reassembly_table,
+ &addresses_reassembly_table_functions);
+ ip_tap = register_tap("ip");
+
+ /* This needs a different (& more user-friendly) name than the other tap */
+ exported_pdu_tap = register_export_pdu_tap_with_encap("IP", WTAP_ENCAP_RAW_IP);
+
+ register_decode_as(&ip_da);
+ register_conversation_table(proto_ip, TRUE, ip_conversation_packet, ip_endpoint_packet);
+ register_conversation_filter("ip", "IPv4", ip_filter_valid, ip_build_filter, NULL);
+
+ ip_cap_handle = register_capture_dissector("ip", capture_ip, proto_ip);
+
+ /* Register IP options as their own protocols so we can get the name of the option */
+ proto_ip_option_eol = proto_register_protocol_in_name_only("IP Option - End of Options List (EOL)", "End of Options List (EOL)", "ip.options.eol", proto_ip, FT_BYTES);
+ proto_ip_option_nop = proto_register_protocol_in_name_only("IP Option - No-Operation (NOP)", "No Operation (NOP)", "ip.options.nop", proto_ip, FT_BYTES);
+ proto_ip_option_security = proto_register_protocol_in_name_only("IP Option - Security", "Security", "ip.options.security", proto_ip, FT_BYTES);
+ proto_ip_option_route = proto_register_protocol_in_name_only("IP Option - Loose Source Route", "Loose Source Route", "ip.options.route", proto_ip, FT_BYTES);
+ proto_ip_option_timestamp = proto_register_protocol_in_name_only("IP Option - Time Stamp", "Time Stamp", "ip.options.timestamp", proto_ip, FT_BYTES);
+ proto_ip_option_ext_security = proto_register_protocol_in_name_only("IP Option - Extended Security", "Extended Security", "ip.options.ext_security", proto_ip, FT_BYTES);
+ proto_ip_option_cipso = proto_register_protocol_in_name_only("IP Option - Commercial Security", "Commercial Security", "ip.options.cipso", proto_ip, FT_BYTES);
+ proto_ip_option_record_route = proto_register_protocol_in_name_only("IP Option - Record Route", "Record Route", "ip.options.record_route", proto_ip, FT_BYTES);
+ proto_ip_option_sid = proto_register_protocol_in_name_only("IP Option - Stream ID", "Stream ID", "ip.options.sid", proto_ip, FT_BYTES);
+ proto_ip_option_source_route = proto_register_protocol_in_name_only("IP Option - Strict Source Route", "Strict Source Route", "ip.options.source_route", proto_ip, FT_BYTES);
+ proto_ip_option_mtu_probe = proto_register_protocol_in_name_only("IP Option - MTU Probe", "MTU Probe", "ip.options.mtu_probe", proto_ip, FT_BYTES);
+ proto_ip_option_mtu_reply = proto_register_protocol_in_name_only("IP Option - MTU Reply", "MTU Reply", "ip.options.mtu_reply", proto_ip, FT_BYTES);
+ proto_ip_option_traceroute = proto_register_protocol_in_name_only("IP Option - Traceroute", "Traceroute", "ip.options.traceroute", proto_ip, FT_BYTES);
+ proto_ip_option_routeralert = proto_register_protocol_in_name_only("IP Option - Router Alert", "Router Alert", "ip.options.routeralert", proto_ip, FT_BYTES);
+ proto_ip_option_sdb = proto_register_protocol_in_name_only("IP Option - Selective Directed Broadcast", "Selective Directed Broadcast", "ip.options.sdb", proto_ip, FT_BYTES);
+ proto_ip_option_qs = proto_register_protocol_in_name_only("IP Option - Quick-Start", "Quick-Start", "ip.options.qs", proto_ip, FT_BYTES);
+}
+
+void
+proto_reg_handoff_ip(void)
+{
+ dissector_handle_t ipv4_handle;
+ capture_dissector_handle_t clip_cap_handle;
+ int proto_clip;
+
+ ipv6_handle = find_dissector("ipv6");
+ ipv4_handle = create_dissector_handle(dissect_ip_v4, proto_ip);
+
+ dissector_add_uint("ethertype", ETHERTYPE_IP, ipv4_handle);
+ dissector_add_uint("erf.types.type", ERF_TYPE_IPV4, ip_handle);
+ dissector_add_uint("ppp.protocol", PPP_IP, ip_handle);
+ dissector_add_uint("ppp.protocol", ETHERTYPE_IP, ip_handle);
+ dissector_add_uint("gre.proto", ETHERTYPE_IP, ip_handle);
+ dissector_add_uint("gre.proto", GRE_WCCP, ip_handle);
+ dissector_add_uint("llc.dsap", SAP_IP, ip_handle);
+ dissector_add_uint("ip.proto", IP_PROTO_IPIP, ip_handle);
+ dissector_add_uint("null.type", BSD_AF_INET, ip_handle);
+ dissector_add_uint("chdlc.protocol", ETHERTYPE_IP, ip_handle);
+ dissector_add_uint("osinl.excl", NLPID_IP, ip_handle);
+ dissector_add_uint("fr.nlpid", NLPID_IP, ip_handle);
+ dissector_add_uint("x.25.spi", NLPID_IP, ip_handle);
+ dissector_add_uint("arcnet.protocol_id", ARCNET_PROTO_IP_1051, ip_handle);
+ dissector_add_uint("arcnet.protocol_id", ARCNET_PROTO_IP_1201, ip_handle);
+ 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", PW_ACH_TYPE_IPV4, ip_handle);
+ dissector_add_uint("mcc.proto", PW_ACH_TYPE_IPV4, ip_handle);
+ dissector_add_uint("sflow_245.header_protocol", SFLOW_245_HEADER_IPv4, ip_handle);
+ dissector_add_uint("l2tp.pw_type", L2TPv3_PW_IP, ip_handle);
+ dissector_add_for_decode_as_with_preference("udp.port", ip_handle);
+ dissector_add_for_decode_as("pcli.payload", ip_handle);
+ dissector_add_uint("wtap_encap", WTAP_ENCAP_RAW_IP4, ip_handle);
+ dissector_add_uint("enc", BSD_AF_INET, ip_handle);
+ dissector_add_uint("vxlan.next_proto", VXLAN_IPV4, ip_handle);
+ dissector_add_uint("nsh.next_proto", NSH_IPV4, ip_handle);
+
+ heur_dissector_add("tipc", dissect_ip_heur, "IP over TIPC", "ip_tipc", proto_ip, HEURISTIC_ENABLE);
+ heur_dissector_add("zbee_zcl_se.tun", dissect_ip_heur, "IP over ZigBee SE Tunneling", "ip_zbee_zcl_se.tun", proto_ip, HEURISTIC_ENABLE);
+
+ capture_dissector_add_uint("ethertype", ETHERTYPE_IP, ip_cap_handle);
+ capture_dissector_add_uint("ax25.pid", AX25_P_IP, ip_cap_handle);
+ capture_dissector_add_uint("enc", BSD_AF_INET, ip_cap_handle);
+ capture_dissector_add_uint("ppp_hdlc", PPP_IP, ip_cap_handle);
+ capture_dissector_add_uint("llc.dsap", SAP_IP, ip_cap_handle);
+ capture_dissector_add_uint("null.bsd", BSD_AF_INET, ip_cap_handle);
+ capture_dissector_add_uint("fr.nlpid", NLPID_IP, ip_cap_handle);
+
+ /* Create dissection function handles for all IP options */
+ dissector_add_uint("ip.option", IPOPT_SEC, create_dissector_handle( dissect_ipopt_security, proto_ip_option_security ));
+ dissector_add_uint("ip.option", IPOPT_LSR, create_dissector_handle( dissect_ipopt_loose_route, proto_ip_option_route ));
+ dissector_add_uint("ip.option", IPOPT_TS, create_dissector_handle( dissect_ipopt_timestamp, proto_ip_option_timestamp ));
+ dissector_add_uint("ip.option", IPOPT_ESEC, create_dissector_handle( dissect_ipopt_ext_security, proto_ip_option_ext_security ));
+ dissector_add_uint("ip.option", IPOPT_CIPSO, create_dissector_handle( dissect_ipopt_cipso, proto_ip_option_cipso ));
+ dissector_add_uint("ip.option", IPOPT_RR, create_dissector_handle( dissect_ipopt_record_route, proto_ip_option_record_route ));
+ dissector_add_uint("ip.option", IPOPT_SID, create_dissector_handle( dissect_ipopt_sid, proto_ip_option_sid ));
+ dissector_add_uint("ip.option", IPOPT_SSR, create_dissector_handle( dissect_ipopt_source_route, proto_ip_option_source_route ));
+ dissector_add_uint("ip.option", IPOPT_MTUP, create_dissector_handle( dissect_ipopt_mtu_probe, proto_ip_option_mtu_probe ));
+ dissector_add_uint("ip.option", IPOPT_MTUR, create_dissector_handle( dissect_ipopt_mtu_reply, proto_ip_option_mtu_reply ));
+ dissector_add_uint("ip.option", IPOPT_TR, create_dissector_handle( dissect_ipopt_tr, proto_ip_option_traceroute ));
+ dissector_add_uint("ip.option", IPOPT_RTRALT, create_dissector_handle( dissect_ipopt_ra, proto_ip_option_routeralert ));
+ dissector_add_uint("ip.option", IPOPT_SDB, create_dissector_handle( dissect_ipopt_sdb, proto_ip_option_sdb ));
+ dissector_add_uint("ip.option", IPOPT_QS, create_dissector_handle( dissect_ipopt_qs, proto_ip_option_qs ));
+
+ /* Classic IP uses the same capture function, but wants its own
+ protocol associated with it. To eliminate linking dependencies,
+ just add it here */
+ proto_clip = proto_get_id_by_filter_name( "clip" );
+ clip_cap_handle = register_capture_dissector("clip", capture_ip, proto_clip);
+ capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_LINUX_ATM_CLIP, clip_cap_handle);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 2
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=2 tabstop=8 expandtab:
+ * :indentSize=2:tabSize=8:noTabs=true:
+ */