/* packet-ipv6.c * Routines for IPv6 packet disassembly * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SHIM6 support added by Matthijs Mekking * * MobileIPv6 support added by Tomislav Borosa * * Added support for new IPv6 Hop by Hop PMTU Option * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "packet-ip.h" #include "packet-juniper.h" #include "packet-sflow.h" #include "packet-vxlan.h" #include "packet-mpls.h" #include "packet-nsh.h" void proto_register_ipv6(void); void proto_reg_handoff_ipv6(void); /* Offsets of fields within an IPv6 header. */ #define IP6H_CTL_VFC 0 #define IP6H_CTL_FLOW 0 #define IP6H_CTL_PLEN 4 #define IP6H_CTL_NXT 6 #define IP6H_CTL_HLIM 7 #define IP6H_SRC 8 #define IP6H_DST 24 /* Option types and related macros */ #define IP6OPT_PAD1 0x00 /* 00 0 00000 = 0 */ #define IP6OPT_PADN 0x01 /* 00 0 00001 = 1 */ #define IP6OPT_TEL 0x04 /* 00 0 00100 = 4 */ #define IP6OPT_RTALERT 0x05 /* 00 0 00101 = 5 */ #define IP6OPT_CALIPSO 0x07 /* 00 0 00111 = 7 */ #define IP6OPT_SMF_DPD 0x08 /* 00 0 01000 = 8 */ #define IP6OPT_PDM 0x0F /* 00 0 01111 = 15 */ #define IP6OPT_APN6 0x13 /* 00 0 10003 = 19 */ #define IP6OPT_EXP_1E 0x1E /* 00 0 11110 = 30 */ #define IP6OPT_QUICKSTART 0x26 /* 00 1 00110 = 38 */ #define IP6OPT_PMTU 0x30 /* 00 1 10000 = 48 */ #define IP6OPT_IOAM 0x31 /* 00 1 10001 = 49 */ #define IP6OPT_EXP_3E 0x3E /* 00 1 11110 = 62 */ #define IP6OPT_TPF 0x41 /* 01 0 00001 = 65 */ #define IP6OPT_EXP_5E 0x5E /* 01 0 11110 = 94 */ #define IP6OPT_RPL 0x63 /* 01 1 00011 = 99 */ #define IP6OPT_MPL 0x6D /* 01 1 01101 = 109 */ #define IP6OPT_EXP_7E 0x7E /* 01 1 11110 = 126 */ #define IP6OPT_ENDI 0x8A /* 10 0 01010 = 138 */ /* DEPRECATED */ #define IP6OPT_ILNP_NONCE 0x8B /* 10 0 01011 = 139 */ #define IP6OPT_LIO 0x8C /* 10 0 01100 = 140 */ #define IP6OPT_EXP_9E 0x9E /* 10 0 11110 = 158 */ #define IP6OPT_EXP_BE 0xBE /* 10 1 11110 = 190 */ #define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ #define IP6OPT_HOME_ADDRESS 0xC9 /* 11 0 01001 = 201 */ #define IP6OPT_EXP_DE 0xDE /* 11 0 11110 = 222 */ #define IP6OPT_IP_DFF 0xEE /* 11 1 01110 = 238 */ #define IP6OPT_EXP_FE 0xFE /* 11 1 11110 = 254 */ #define IP6OPT_RTALERT_MLD 0 /* Datagram contains MLD msg */ #define IP6OPT_RTALERT_RSVP 1 /* Datagram contains RSVP msg */ #define IP6OPT_RTALERT_ACTNET 2 /* Datagram contains ACTNET msg */ /* RPL Routing header */ #define IP6RRPL_BITMASK_CMPRI 0xF0000000 #define IP6RRPL_BITMASK_CMPRE 0x0F000000 #define IP6RRPL_BITMASK_PAD 0x00F00000 #define IP6RRPL_BITMASK_RESERVED 0x000FFFFF /* IOAM Option-Types */ #define IP6IOAM_PRE_TRACE 0 /* Pre-allocated Trace */ #define IP6IOAM_INC_TRACE 1 /* Incremental Trace */ #define IP6IOAM_POT 2 /* Proof of Transit */ #define IP6IOAM_E2E 3 /* Edge to Edge */ /* IOAM Trace Types */ #define IP6IOAM_TRACE_MASK_BIT0 (1 << 23) /* Hop_lim + Node ID */ #define IP6IOAM_TRACE_MASK_BIT1 (1 << 22) /* Ingress and Egress IDs */ #define IP6IOAM_TRACE_MASK_BIT2 (1 << 21) /* Timestamp seconds */ #define IP6IOAM_TRACE_MASK_BIT3 (1 << 20) /* Timestamp fraction */ #define IP6IOAM_TRACE_MASK_BIT4 (1 << 19) /* Transit delay */ #define IP6IOAM_TRACE_MASK_BIT5 (1 << 18) /* IOAM-Namespace data */ #define IP6IOAM_TRACE_MASK_BIT6 (1 << 17) /* Queue depth */ #define IP6IOAM_TRACE_MASK_BIT7 (1 << 16) /* Checksum complement */ #define IP6IOAM_TRACE_MASK_BIT8 (1 << 15) /* (wide) Hop_lim + Node ID */ #define IP6IOAM_TRACE_MASK_BIT9 (1 << 14) /* (wide) Ingress and Egress IDs */ #define IP6IOAM_TRACE_MASK_BIT10 (1 << 13) /* (wide) IOAM-Namespace data */ #define IP6IOAM_TRACE_MASK_BIT11 (1 << 12) /* Buffer occupancy */ #define IP6IOAM_TRACE_MASK_BIT12 (1 << 11) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT13 (1 << 10) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT14 (1 << 9) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT15 (1 << 8) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT16 (1 << 7) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT17 (1 << 6) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT18 (1 << 5) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT19 (1 << 4) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT20 (1 << 3) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT21 (1 << 2) /* Undefined */ #define IP6IOAM_TRACE_MASK_BIT22 (1 << 1) /* Opaque state snapshot */ /* Protocol specific data indices */ #define IPV6_PROTO_VALUE 1 #define IPV6_PROTO_PINFO 2 static int ipv6_tap = -1; static int exported_pdu_tap = -1; static int proto_ipv6 = -1; static int proto_ipv6_hopopts = -1; static int proto_ipv6_routing = -1; static int proto_ipv6_fraghdr = -1; static int proto_ipv6_dstopts = -1; static int proto_ipv6_routing_rt0 = -1; static int proto_ipv6_routing_mipv6 = -1; static int proto_ipv6_routing_rpl = -1; static int proto_ipv6_routing_srh = -1; static int proto_ipv6_routing_crh = -1; static int hf_ipv6_version = -1; static int hf_ip_version = -1; static int hf_ipv6_tclass = -1; static int hf_ipv6_tclass_dscp = -1; static int hf_ipv6_tclass_ecn = -1; static int hf_ipv6_flow = -1; static int hf_ipv6_plen = -1; static int hf_ipv6_nxt = -1; static int hf_ipv6_hlim = -1; static int hf_ipv6_src = -1; static int hf_ipv6_src_addr_space = -1; static int hf_ipv6_src_multicast_flags = -1; static int hf_ipv6_src_multicast_flags_reserved = -1; static int hf_ipv6_src_multicast_flags_transient = -1; static int hf_ipv6_src_multicast_flags_network_prefix = -1; static int hf_ipv6_src_multicast_flags_embed_rp = -1; static int hf_ipv6_src_special_purpose = -1; static int hf_ipv6_src_multicast_scope = -1; static int hf_ipv6_src_host = -1; static int hf_ipv6_src_slaac_mac = -1; static int hf_ipv6_src_isatap_ipv4 = -1; static int hf_ipv6_src_6to4_gateway_ipv4 = -1; static int hf_ipv6_src_6to4_sla_id = -1; static int hf_ipv6_src_teredo_server_ipv4 = -1; static int hf_ipv6_src_teredo_port = -1; static int hf_ipv6_src_teredo_client_ipv4 = -1; static int hf_ipv6_src_embed_ipv4 = -1; static int hf_ipv6_dst = -1; static int hf_ipv6_dst_addr_space = -1; static int hf_ipv6_dst_multicast_flags = -1; static int hf_ipv6_dst_multicast_flags_reserved = -1; static int hf_ipv6_dst_multicast_flags_transient = -1; static int hf_ipv6_dst_multicast_flags_network_prefix = -1; static int hf_ipv6_dst_multicast_flags_embed_rp = -1; static int hf_ipv6_dst_multicast_scope = -1; static int hf_ipv6_dst_special_purpose = -1; static int hf_ipv6_dst_host = -1; static int hf_ipv6_dst_slaac_mac = -1; static int hf_ipv6_dst_isatap_ipv4 = -1; static int hf_ipv6_dst_6to4_gateway_ipv4 = -1; static int hf_ipv6_dst_6to4_sla_id = -1; static int hf_ipv6_dst_teredo_server_ipv4 = -1; static int hf_ipv6_dst_teredo_port = -1; static int hf_ipv6_dst_teredo_client_ipv4 = -1; static int hf_ipv6_dst_embed_ipv4 = -1; static int hf_ipv6_addr = -1; static int hf_ipv6_addr_space = -1; static int hf_ipv6_multicast_flags = -1; static int hf_ipv6_multicast_flags_reserved = -1; static int hf_ipv6_multicast_flags_transient = -1; static int hf_ipv6_multicast_flags_network_prefix = -1; static int hf_ipv6_multicast_flags_embed_rp = -1; static int hf_ipv6_multicast_scope = -1; static int hf_ipv6_addr_special_purpose = -1; static int hf_ipv6_host = -1; static int hf_ipv6_slaac_mac = -1; static int hf_ipv6_isatap_ipv4 = -1; static int hf_ipv6_6to4_gateway_ipv4 = -1; static int hf_ipv6_6to4_sla_id = -1; static int hf_ipv6_teredo_server_ipv4 = -1; static int hf_ipv6_teredo_port = -1; static int hf_ipv6_teredo_client_ipv4 = -1; static int hf_ipv6_embed_ipv4_prefix = -1; static int hf_ipv6_embed_ipv4 = -1; static int hf_ipv6_embed_ipv4_u = -1; static int hf_ipv6_embed_ipv4_suffix = -1; static int hf_ipv6_opt = -1; static int hf_ipv6_opt_type = -1; static int hf_ipv6_opt_type_action = -1; static int hf_ipv6_opt_type_change = -1; static int hf_ipv6_opt_type_rest = -1; static int hf_ipv6_opt_length = -1; static int hf_ipv6_opt_pad1 = -1; static int hf_ipv6_opt_padn = -1; static int hf_ipv6_opt_tel = -1; static int hf_ipv6_opt_rtalert = -1; static int hf_ipv6_opt_pmtu_min = -1; static int hf_ipv6_opt_pmtu_rtn = -1; static int hf_ipv6_opt_pmtu_rtn_flag = -1; static int hf_ipv6_opt_apn_id_type = -1; static int hf_ipv6_opt_apn_flags = -1; static int hf_ipv6_opt_apn_param_type = -1; static int hf_ipv6_opt_apn_id_part1 = -1; static int hf_ipv6_opt_apn_id_part2 = -1; static int hf_ipv6_opt_apn_id_part3 = -1; static int hf_ipv6_opt_apn_id_part4 = -1; static int hf_ipv6_opt_jumbo = -1; static int hf_ipv6_opt_calipso_doi = -1; static int hf_ipv6_opt_calipso_cmpt_length = -1; static int hf_ipv6_opt_calipso_sens_level = -1; static int hf_ipv6_opt_calipso_checksum = -1; static int hf_ipv6_opt_calipso_cmpt_bitmap = -1; static int hf_ipv6_opt_smf_dpd_hash_bit = -1; static int hf_ipv6_opt_smf_dpd_tid_type = -1; static int hf_ipv6_opt_smf_dpd_tid_len = -1; static int hf_ipv6_opt_smf_dpd_tagger_id = -1; static int hf_ipv6_opt_smf_dpd_ident = -1; static int hf_ipv6_opt_smf_dpd_hav = -1; static int hf_ipv6_opt_pdm_scale_dtlr = -1; static int hf_ipv6_opt_pdm_scale_dtls = -1; static int hf_ipv6_opt_pdm_psn_this_pkt = -1; static int hf_ipv6_opt_pdm_psn_last_recv = -1; static int hf_ipv6_opt_pdm_delta_last_recv = -1; static int hf_ipv6_opt_pdm_delta_last_sent = -1; static int hf_ipv6_opt_qs_func = -1; static int hf_ipv6_opt_qs_rate = -1; static int hf_ipv6_opt_qs_ttl = -1; static int hf_ipv6_opt_qs_ttl_diff = -1; static int hf_ipv6_opt_qs_unused = -1; static int hf_ipv6_opt_qs_nonce = -1; static int hf_ipv6_opt_qs_reserved = -1; static int hf_ipv6_opt_ioam_rsv = -1; static int hf_ipv6_opt_ioam_opt_type = -1; static int hf_ipv6_opt_ioam_trace_ns = -1; static int hf_ipv6_opt_ioam_trace_nodelen = -1; static int hf_ipv6_opt_ioam_trace_flags = -1; static int hf_ipv6_opt_ioam_trace_flag_o = -1; static int hf_ipv6_opt_ioam_trace_flag_l = -1; static int hf_ipv6_opt_ioam_trace_flag_a = -1; static int hf_ipv6_opt_ioam_trace_flag_rsv = -1; static int hf_ipv6_opt_ioam_trace_remlen = -1; static int hf_ipv6_opt_ioam_trace_type = -1; static int hf_ipv6_opt_ioam_trace_type_bit0 = -1; static int hf_ipv6_opt_ioam_trace_type_bit1 = -1; static int hf_ipv6_opt_ioam_trace_type_bit2 = -1; static int hf_ipv6_opt_ioam_trace_type_bit3 = -1; static int hf_ipv6_opt_ioam_trace_type_bit4 = -1; static int hf_ipv6_opt_ioam_trace_type_bit5 = -1; static int hf_ipv6_opt_ioam_trace_type_bit6 = -1; static int hf_ipv6_opt_ioam_trace_type_bit7 = -1; static int hf_ipv6_opt_ioam_trace_type_bit8 = -1; static int hf_ipv6_opt_ioam_trace_type_bit9 = -1; static int hf_ipv6_opt_ioam_trace_type_bit10 = -1; static int hf_ipv6_opt_ioam_trace_type_bit11 = -1; static int hf_ipv6_opt_ioam_trace_type_undef = -1; static int hf_ipv6_opt_ioam_trace_type_bit22 = -1; static int hf_ipv6_opt_ioam_trace_type_rsv = -1; static int hf_ipv6_opt_ioam_trace_rsv = -1; static int hf_ipv6_opt_ioam_trace_free_space = -1; static int hf_ipv6_opt_ioam_trace_node_hlim = -1; static int hf_ipv6_opt_ioam_trace_node_id = -1; static int hf_ipv6_opt_ioam_trace_node_iif = -1; static int hf_ipv6_opt_ioam_trace_node_eif = -1; static int hf_ipv6_opt_ioam_trace_node_tss = -1; static int hf_ipv6_opt_ioam_trace_node_tsf = -1; static int hf_ipv6_opt_ioam_trace_node_trdelay = -1; static int hf_ipv6_opt_ioam_trace_node_nsdata = -1; static int hf_ipv6_opt_ioam_trace_node_qdepth = -1; static int hf_ipv6_opt_ioam_trace_node_csum = -1; static int hf_ipv6_opt_ioam_trace_node_id_wide = -1; static int hf_ipv6_opt_ioam_trace_node_iif_wide = -1; static int hf_ipv6_opt_ioam_trace_node_eif_wide = -1; static int hf_ipv6_opt_ioam_trace_node_nsdata_wide = -1; static int hf_ipv6_opt_ioam_trace_node_bufoccup = -1; static int hf_ipv6_opt_ioam_trace_node_undefined = -1; static int hf_ipv6_opt_ioam_trace_node_oss_len = -1; static int hf_ipv6_opt_ioam_trace_node_oss_scid = -1; static int hf_ipv6_opt_ioam_trace_node_oss_data = -1; static int hf_ipv6_opt_tpf_information = -1; static int hf_ipv6_opt_mipv6_home_address = -1; static int hf_ipv6_opt_rpl_flag = -1; static int hf_ipv6_opt_rpl_flag_o = -1; static int hf_ipv6_opt_rpl_flag_r = -1; static int hf_ipv6_opt_rpl_flag_f = -1; static int hf_ipv6_opt_rpl_flag_rsv = -1; static int hf_ipv6_opt_rpl_instance_id = -1; static int hf_ipv6_opt_rpl_senderrank = -1; static int hf_ipv6_opt_ilnp_nonce = -1; static int hf_ipv6_opt_lio_len = -1; static int hf_ipv6_opt_lio_id = -1; static int hf_ipv6_opt_mpl_flag = -1; static int hf_ipv6_opt_mpl_flag_s = -1; static int hf_ipv6_opt_mpl_flag_m = -1; static int hf_ipv6_opt_mpl_flag_v = -1; static int hf_ipv6_opt_mpl_flag_rsv = -1; static int hf_ipv6_opt_mpl_sequence = -1; static int hf_ipv6_opt_mpl_seed_id = -1; static int hf_ipv6_opt_dff_flags = -1; static int hf_ipv6_opt_dff_flag_ver = -1; static int hf_ipv6_opt_dff_flag_dup = -1; static int hf_ipv6_opt_dff_flag_ret = -1; static int hf_ipv6_opt_dff_flag_rsv = -1; static int hf_ipv6_opt_dff_seqnum = -1; static int hf_ipv6_opt_experimental = -1; static int hf_ipv6_opt_unknown_data = -1; static int hf_ipv6_opt_unknown = -1; static int hf_ipv6_dstopts_nxt = -1; static int hf_ipv6_dstopts_len = -1; static int hf_ipv6_dstopts_len_oct = -1; static int hf_ipv6_hopopts_nxt = -1; static int hf_ipv6_hopopts_len = -1; static int hf_ipv6_hopopts_len_oct = -1; static int hf_ipv6_routing_nxt = -1; static int hf_ipv6_routing_len = -1; static int hf_ipv6_routing_len_oct = -1; static int hf_ipv6_routing_type = -1; static int hf_ipv6_routing_segleft = -1; static int hf_ipv6_routing_unknown_data = -1; static int hf_ipv6_fraghdr_nxt = -1; static int hf_ipv6_fraghdr_reserved_octet = -1; static int hf_ipv6_fraghdr_offset = -1; static int hf_ipv6_fraghdr_reserved_bits = -1; static int hf_ipv6_fraghdr_more = -1; static int hf_ipv6_fraghdr_ident = -1; static int hf_ipv6_fragment = -1; static int hf_ipv6_fragment_overlap = -1; static int hf_ipv6_fragment_overlap_conflict = -1; static int hf_ipv6_fragment_multiple_tails = -1; static int hf_ipv6_fragment_too_long_fragment = -1; static int hf_ipv6_fragment_error = -1; static int hf_ipv6_fragment_count = -1; static int hf_ipv6_fragments = -1; static int hf_ipv6_reassembled_in = -1; static int hf_ipv6_reassembled_length = -1; static int hf_ipv6_reassembled_data = -1; static int hf_ipv6_routing_src_reserved = -1; static int hf_ipv6_routing_src_addr = -1; static int hf_ipv6_routing_mipv6_reserved = -1; static int hf_ipv6_routing_mipv6_home_address = -1; static int hf_ipv6_routing_rpl_cmprI = -1; static int hf_ipv6_routing_rpl_cmprE = -1; static int hf_ipv6_routing_rpl_pad = -1; static int hf_ipv6_routing_rpl_reserved = -1; static int hf_ipv6_routing_rpl_addr_count = -1; static int hf_ipv6_routing_rpl_addr = -1; static int hf_ipv6_routing_rpl_fulladdr = -1; static int hf_ipv6_routing_srh_last_entry = -1; static int hf_ipv6_routing_srh_flags = -1; static int hf_ipv6_routing_srh_tag = -1; static int hf_ipv6_routing_srh_addr = -1; static int hf_ipv6_routing_crh16_current_sid = -1; static int hf_ipv6_routing_crh32_current_sid = -1; static int hf_ipv6_routing_crh16_segment_id = -1; static int hf_ipv6_routing_crh32_segment_id = -1; struct ipv6_addr_info_s { int *hf_addr; int *hf_addr_space; int *hf_multicast_flags; int *const *hf_multicast_flags_bits; int *hf_multicast_scope; int *hf_special_purpose; int *hf_host; }; static int *const ipv6_src_multicast_flags_bits[5] = { &hf_ipv6_src_multicast_flags_reserved, &hf_ipv6_src_multicast_flags_embed_rp, &hf_ipv6_src_multicast_flags_network_prefix, &hf_ipv6_src_multicast_flags_transient, NULL }; static struct ipv6_addr_info_s ipv6_src_info = { &hf_ipv6_src, &hf_ipv6_src_addr_space, &hf_ipv6_src_multicast_flags, ipv6_src_multicast_flags_bits, &hf_ipv6_src_multicast_scope, &hf_ipv6_src_special_purpose, &hf_ipv6_src_host, }; static int *const ipv6_dst_multicast_flags_bits[5] = { &hf_ipv6_dst_multicast_flags_reserved, &hf_ipv6_dst_multicast_flags_embed_rp, &hf_ipv6_dst_multicast_flags_network_prefix, &hf_ipv6_dst_multicast_flags_transient, NULL }; static struct ipv6_addr_info_s ipv6_dst_info = { &hf_ipv6_dst, &hf_ipv6_dst_addr_space, &hf_ipv6_dst_multicast_flags, ipv6_dst_multicast_flags_bits, &hf_ipv6_dst_multicast_scope, &hf_ipv6_dst_special_purpose, &hf_ipv6_dst_host, }; 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_ipv6_proto = -1; static gint ett_ipv6_detail = -1; static gint ett_ipv6_multicast_flags = -1; static gint ett_ipv6_traffic_class = -1; static gint ett_ipv6_opt = -1; static gint ett_ipv6_opt_type = -1; static gint ett_ipv6_opt_rpl = -1; static gint ett_ipv6_opt_mpl = -1; static gint ett_ipv6_opt_dff_flags = -1; static gint ett_ipv6_opt_ioam_trace_flags = -1; static gint ett_ipv6_opt_ioam_trace_types = -1; static gint ett_ipv6_hopopts_proto = -1; static gint ett_ipv6_fraghdr_proto = -1; static gint ett_ipv6_routing_proto = -1; static gint ett_ipv6_routing_srh_vect = -1; static gint ett_ipv6_fragments = -1; static gint ett_ipv6_fragment = -1; static gint ett_ipv6_dstopts_proto = -1; static gint ett_geoip_info = -1; static expert_field ei_ipv6_routing_invalid_length = EI_INIT; static expert_field ei_ipv6_routing_invalid_segleft = EI_INIT; static expert_field ei_ipv6_routing_undecoded = EI_INIT; static expert_field ei_ipv6_dst_addr_not_unspecified = EI_INIT; static expert_field ei_ipv6_src_addr_not_multicast = EI_INIT; static expert_field ei_ipv6_dst_addr_not_multicast = EI_INIT; static expert_field ei_ipv6_src_route_list_mult_inst_same_addr = EI_INIT; static expert_field ei_ipv6_src_route_list_src_addr = EI_INIT; static expert_field ei_ipv6_src_route_list_dst_addr = EI_INIT; static expert_field ei_ipv6_src_route_list_multicast_addr = EI_INIT; static expert_field ei_ipv6_routing_rpl_cmpri_cmpre_pad = EI_INIT; static expert_field ei_ipv6_routing_rpl_addr_count_ge0 = EI_INIT; static expert_field ei_ipv6_routing_rpl_reserved = EI_INIT; static expert_field ei_ipv6_routing_deprecated = EI_INIT; static expert_field ei_ipv6_opt_jumbo_missing = EI_INIT; static expert_field ei_ipv6_opt_jumbo_prohibited = EI_INIT; static expert_field ei_ipv6_opt_jumbo_truncated = EI_INIT; static expert_field ei_ipv6_opt_jumbo_fragment = EI_INIT; static expert_field ei_ipv6_opt_invalid_len = EI_INIT; static expert_field ei_ipv6_opt_apn_invalid_id_type = EI_INIT; static expert_field ei_ipv6_opt_unknown_data = EI_INIT; static expert_field ei_ipv6_opt_deprecated = EI_INIT; static expert_field ei_ipv6_opt_mpl_ipv6_src_seed_id = EI_INIT; static expert_field ei_ipv6_hopopts_not_first = EI_INIT; static expert_field ei_ipv6_plen_exceeds_framing = EI_INIT; static expert_field ei_ipv6_plen_zero = EI_INIT; static expert_field ei_ipv6_bogus_ipv6_version = EI_INIT; static expert_field ei_ipv6_invalid_header = EI_INIT; static expert_field ei_ipv6_opt_header_mismatch = EI_INIT; static expert_field ei_ipv6_opt_ioam_invalid_nodelen = EI_INIT; static expert_field ei_ipv6_opt_ioam_invalid_remlen = EI_INIT; static expert_field ei_ipv6_opt_ioam_invalid_trace_type = EI_INIT; static expert_field ei_ipv6_embed_ipv4_u_value = EI_INIT; static dissector_handle_t ipv6_handle; #define set_address_ipv6(dst, src_ip6) \ set_address((dst), AT_IPv6, IPv6_ADDR_SIZE, (src_ip6)) #define set_address_ipv6_tvb(dst, tvb, offset) \ set_address_tvb((dst), AT_IPv6, IPv6_ADDR_SIZE, (tvb), (offset)) #define alloc_address_wmem_ipv6(scope, dst, src_ip6) \ alloc_address_wmem((scope), (dst), AT_IPv6, IPv6_ADDR_SIZE, (src_ip6)) #define alloc_address_tvb_ipv6(scope, dst, tvb, offset) \ alloc_address_tvb((scope), (dst), AT_IPv6, IPv6_ADDR_SIZE, (tvb), (offset)) extern const ws_in6_addr *tvb_get_ptr_ipv6(tvbuff_t tvb, int offset); #define tvb_get_ptr_ipv6(tvb, offset) \ ((const ws_in6_addr *)tvb_get_ptr(tvb, offset, IPv6_ADDR_SIZE)) ipv6_pinfo_t *p_get_ipv6_pinfo(packet_info *pinfo) { return (ipv6_pinfo_t *)p_get_proto_data(pinfo->pool, pinfo, proto_ipv6, IPV6_PROTO_PINFO); } /* Return tree pointer (for tree root preference) */ proto_tree *p_ipv6_pinfo_select_root(packet_info *pinfo, proto_tree *tree) { ipv6_pinfo_t *p; if ((p = p_get_ipv6_pinfo(pinfo)) != NULL && p->ipv6_tree != NULL) return p->ipv6_tree; return tree; } ipv6_pinfo_t *p_ipv6_pinfo_add_len(packet_info *pinfo, int exthdr_len) { ipv6_pinfo_t *p; if ((p = p_get_ipv6_pinfo(pinfo)) == NULL) return NULL; p->frag_plen -= exthdr_len; p->ipv6_item_len += exthdr_len; return p; } static void p_add_ipv6_nxt(packet_info *pinfo, guint8 nxt) { guint8 *ptr; ptr = (guint8 *)wmem_memdup(pinfo->pool, &nxt, sizeof(guint8)); p_add_proto_data(pinfo->pool, pinfo, proto_ipv6, (pinfo->curr_layer_num<<8) | IPV6_PROTO_VALUE, ptr); } static guint8 *p_get_ipv6_nxt(packet_info *pinfo) { return (guint8 *)p_get_proto_data(pinfo->pool, pinfo, proto_ipv6, (pinfo->curr_layer_num<<8) | IPV6_PROTO_VALUE); } static gpointer ipv6_value(packet_info *pinfo) { guint8 *nxt = p_get_ipv6_nxt(pinfo); if (nxt == NULL) { return GUINT_TO_POINTER(255); /* Reserved IP Protocol */ } return GUINT_TO_POINTER((guint)*nxt); } static void ipv6_prompt(packet_info *pinfo, gchar *result) { gpointer value = ipv6_value(pinfo); snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "IP protocol %u as", GPOINTER_TO_UINT(value)); } static const char* ipv6_conv_get_filter_type(conv_item_t* conv, conv_filter_type_e filter) { if ((filter == CONV_FT_SRC_ADDRESS) && (conv->src_address.type == AT_IPv6)) return "ipv6.src"; if ((filter == CONV_FT_DST_ADDRESS) && (conv->dst_address.type == AT_IPv6)) return "ipv6.dst"; if ((filter == CONV_FT_ANY_ADDRESS) && (conv->src_address.type == AT_IPv6)) return "ipv6.addr"; return CONV_FILTER_INVALID; } static ct_dissector_info_t ipv6_ct_dissector_info = {&ipv6_conv_get_filter_type}; static tap_packet_status ipv6_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 ipv6_tap_info_t *ip6 = (const ipv6_tap_info_t *)vip; add_conversation_table_data(hash, &ip6->ip6_src, &ip6->ip6_dst, 0, 0, 1, pinfo->fd->pkt_len, &pinfo->rel_ts, &pinfo->abs_ts, &ipv6_ct_dissector_info, CONVERSATION_NONE); return TAP_PACKET_REDRAW; } static const char* ipv6_endpoint_get_filter_type(endpoint_item_t* endpoint, conv_filter_type_e filter) { if ((filter == CONV_FT_ANY_ADDRESS) && (endpoint->myaddress.type == AT_IPv6)) return "ipv6.addr"; return CONV_FILTER_INVALID; } static et_dissector_info_t ipv6_endpoint_dissector_info = {&ipv6_endpoint_get_filter_type}; static tap_packet_status ipv6_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 ipv6_tap_info_t *ip6 = (const ipv6_tap_info_t *)vip; add_endpoint_table_data(hash, &ip6->ip6_src, 0, TRUE, 1, pinfo->fd->pkt_len, &ipv6_endpoint_dissector_info, ENDPOINT_NONE); add_endpoint_table_data(hash, &ip6->ip6_dst, 0, FALSE, 1, pinfo->fd->pkt_len, &ipv6_endpoint_dissector_info, ENDPOINT_NONE); return TAP_PACKET_REDRAW; } static gboolean ipv6_filter_valid(packet_info *pinfo) { return proto_is_frame_protocol(pinfo->layers, "ipv6"); } static gchar* ipv6_build_filter(packet_info *pinfo) { return ws_strdup_printf("ipv6.addr eq %s and ipv6.addr eq %s", address_to_str(pinfo->pool, &pinfo->net_src), address_to_str(pinfo->pool, &pinfo->net_dst)); } /* UAT for providing a list of NAT64 prefixes */ struct nat64_prefix_data { char *ipaddr; uint8_t prefix_len; uint32_t prefix_wildcard_len; }; static uat_t *nat64_prefix_uat = NULL; static struct nat64_prefix_data *nat64_prefix_uats = NULL; static guint number_of_nat64_prefix = 0; UAT_CSTRING_CB_DEF(nat64_prefix_uats, ipaddr, struct nat64_prefix_data) static gboolean nat64_prefix_uat_fld_ip_chk_cb(void *r _U_, const char *ipaddr, guint len _U_, const void *u1 _U_, const void *u2 _U_, char **err) { /* Check for a valid IPv6 address */ ws_in6_addr addr; if (ws_inet_pton6(ipaddr, &addr)) { *err = NULL; return TRUE; } *err = ws_strdup_printf("No valid IPv6 address given."); return FALSE; } static const value_string nat64_prefix_length_vals[] = { { 32, "32" }, { 40, "40" }, { 48, "48" }, { 56, "56" }, { 64, "64" }, { 96, "96" }, { 0, NULL } }; UAT_VS_DEF(nat64_prefix_uats, prefix_len, struct nat64_prefix_data, uint8_t, 96, "96") static const value_string nat64_prefix_wildcard_length_vals[] = { { 0, "0" }, { 8, "8" }, { 16, "16" }, { 32, "32" }, { 64, "64" }, { 0, NULL } }; UAT_VS_DEF(nat64_prefix_uats, prefix_wildcard_len, struct nat64_prefix_data, uint8_t, 0, "0") static void nat64_prefix_free_cb(void *data) { struct nat64_prefix_data *h = (struct nat64_prefix_data *)data; g_free(h->ipaddr); } static void * nat64_prefix_copy_cb(void *dst_, const void *src_, size_t len _U_) { const struct nat64_prefix_data *src = (const struct nat64_prefix_data *)src_; struct nat64_prefix_data *dst = (struct nat64_prefix_data *)dst_; dst->ipaddr = g_strdup(src->ipaddr); dst->prefix_len = src->prefix_len; dst->prefix_wildcard_len = src->prefix_wildcard_len; return dst; } static gint ipv6_previous_layer_id(packet_info *pinfo) { wmem_list_frame_t *layer; layer = wmem_list_tail(pinfo->layers); DISSECTOR_ASSERT(layer); layer = wmem_list_frame_prev(layer); if (layer != NULL) { return GPOINTER_TO_INT(wmem_list_frame_data(layer)); } return -1; } static const fragment_items ipv6_frag_items = { &ett_ipv6_fragment, &ett_ipv6_fragments, &hf_ipv6_fragments, &hf_ipv6_fragment, &hf_ipv6_fragment_overlap, &hf_ipv6_fragment_overlap_conflict, &hf_ipv6_fragment_multiple_tails, &hf_ipv6_fragment_too_long_fragment, &hf_ipv6_fragment_error, &hf_ipv6_fragment_count, &hf_ipv6_reassembled_in, &hf_ipv6_reassembled_length, &hf_ipv6_reassembled_data, "IPv6 fragments" }; static dissector_table_t ip_dissector_table; static dissector_table_t ipv6_routing_dissector_table; /* Reassemble fragmented datagrams */ static gboolean ipv6_reassemble = TRUE; /* Place IPv6 summary in proto tree */ static gboolean ipv6_summary_in_tree = TRUE; /* Show expanded information about IPv6 address */ static gboolean ipv6_address_detail = FALSE; /* Look up addresses via mmdbresolve */ static gboolean ipv6_use_geoip = TRUE; /* Perform strict RFC adherence checking */ static gboolean g_ipv6_rpl_srh_strict_rfc_checking = FALSE; /* Use heuristics to determine subdissector */ static gboolean try_heuristic_first = FALSE; /* Display IPv6 extension headers under the root tree */ static gboolean ipv6_exthdr_under_root = FALSE; /* Hide extension header generated field for length */ static gboolean ipv6_exthdr_hide_len_oct_field = FALSE; /* Assume TSO and correct zero-length IP packets */ static gboolean ipv6_tso_supported = FALSE; /* * defragmentation of IPv6 */ static reassembly_table ipv6_reassembly_table; /* http://www.iana.org/assignments/ipv6-parameters (last updated 2015-07-07) */ static const value_string ipv6_opt_type_vals[] = { { IP6OPT_PAD1, "Pad1" }, { IP6OPT_PADN, "PadN" }, { IP6OPT_TEL, "Tunnel Encapsulation Limit" }, { IP6OPT_RTALERT, "Router Alert" }, { IP6OPT_CALIPSO, "CALIPSO" }, { IP6OPT_SMF_DPD, "SMF_DPD" }, { IP6OPT_PDM, "Performance and Diagnostic Metrics" }, { IP6OPT_APN6, "Application-Aware IPv6 Networking (APN6)" }, { IP6OPT_EXP_1E, "Experimental (0x1E)" }, { IP6OPT_QUICKSTART, "Quick-Start" }, { IP6OPT_PMTU, "Path MTU Option" }, { IP6OPT_IOAM, "IOAM Option" }, { IP6OPT_EXP_3E, "Experimental (0x3E)" }, { IP6OPT_TPF, "Tunnel Payload Forwarding (TPF) Information" }, { IP6OPT_EXP_5E, "Experimental (0x5E)" }, { IP6OPT_RPL, "RPL Option" }, { IP6OPT_MPL, "MPL Option" }, { IP6OPT_EXP_7E, "Experimental (0x7E)" }, { IP6OPT_ENDI, "Endpoint Identification" }, { IP6OPT_ILNP_NONCE, "ILNP Nonce" }, { IP6OPT_LIO, "Line-Identification Option" }, { IP6OPT_EXP_9E, "Experimental (0x9E)" }, { IP6OPT_EXP_BE, "Experimental (0xBE)" }, { IP6OPT_JUMBO, "Jumbo Payload" }, { IP6OPT_HOME_ADDRESS, "Home Address" }, { IP6OPT_EXP_DE, "Experimental (0xDE)" }, { IP6OPT_IP_DFF, "IP_DFF" }, { IP6OPT_EXP_FE, "Experimental (0xFE)" }, { 0, NULL } }; static value_string_ext ipv6_opt_type_vals_ext = VALUE_STRING_EXT_INIT(ipv6_opt_type_vals); static const value_string ipv6_opt_rtalert_vals[] = { { IP6OPT_RTALERT_MLD, "MLD" }, { IP6OPT_RTALERT_RSVP, "RSVP" }, { IP6OPT_RTALERT_ACTNET, "Active Network" }, { 0, NULL } }; enum { IP6OPT_SMF_DPD_NULL = 0, IP6OPT_SMF_DPD_DFLT, IP6OPT_SMF_DPD_IPv4, IP6OPT_SMF_DPD_IPv6 }; static const value_string ipv6_opt_smf_dpd_tidty_vals[] = { { IP6OPT_SMF_DPD_NULL, "NULL" }, { IP6OPT_SMF_DPD_DFLT, "DEFAULT" }, { IP6OPT_SMF_DPD_IPv4, "IPv4" }, { IP6OPT_SMF_DPD_IPv6, "IPv6" }, { 0, NULL } }; enum { IPv6_OPT_ACTION_SKIP = 0, IPv6_OPT_ACTION_DISC, IPv6_OPT_ACTION_ICMP, IPv6_OPT_ACTION_MCST, }; static const value_string ipv6_opt_type_action_vals[] = { { IPv6_OPT_ACTION_SKIP, "Skip and continue" }, { IPv6_OPT_ACTION_DISC, "Discard" }, { IPv6_OPT_ACTION_ICMP, "Discard and send ICMP Parameter Problem" }, { IPv6_OPT_ACTION_MCST, "Discard and send ICMP if not multicast" }, { 0, NULL } }; enum { IPv6_OPT_HDR_HBH = 0, IPv6_OPT_HDR_DST, IPv6_OPT_HDR_ANY }; static const gint _ipv6_opt_type_hdr[][2] = { { IP6OPT_TEL, IPv6_OPT_HDR_DST }, { IP6OPT_RTALERT, IPv6_OPT_HDR_HBH }, { IP6OPT_PMTU, IPv6_OPT_HDR_HBH }, { IP6OPT_APN6, IPv6_OPT_HDR_ANY }, { IP6OPT_CALIPSO, IPv6_OPT_HDR_HBH }, { IP6OPT_SMF_DPD, IPv6_OPT_HDR_HBH }, { IP6OPT_PDM, IPv6_OPT_HDR_DST }, { IP6OPT_QUICKSTART, IPv6_OPT_HDR_HBH }, { IP6OPT_IOAM, IPv6_OPT_HDR_HBH }, { IP6OPT_TPF, IPv6_OPT_HDR_DST }, { IP6OPT_RPL, IPv6_OPT_HDR_HBH }, { IP6OPT_MPL, IPv6_OPT_HDR_HBH }, { IP6OPT_ILNP_NONCE, IPv6_OPT_HDR_DST }, { IP6OPT_LIO, IPv6_OPT_HDR_DST }, { IP6OPT_JUMBO, IPv6_OPT_HDR_HBH }, { IP6OPT_HOME_ADDRESS, IPv6_OPT_HDR_DST }, { IP6OPT_IP_DFF, IPv6_OPT_HDR_HBH }, { 0, IPv6_OPT_HDR_ANY } }; static inline gint ipv6_opt_type_hdr(gint type) { const gint (*p)[2] = _ipv6_opt_type_hdr; for (; (*p)[1] != IPv6_OPT_HDR_ANY; p++) { if ((*p)[0] == type) { return (*p)[1]; } } return IPv6_OPT_HDR_ANY; } enum { IPv6_RT_HEADER_SOURCE_ROUTING = 0, /* DEPRECATED */ IPv6_RT_HEADER_NIMROD = 1, /* DEPRECATED */ IPv6_RT_HEADER_MOBILE_IP = 2, IPv6_RT_HEADER_RPL = 3, IPv6_RT_HEADER_SEGMENT_ROUTING = 4, IPv6_RT_HEADER_COMPACT_16 = 5, IPv6_RT_HEADER_COMPACT_32 = 6, IPv6_RT_HEADER_EXP1 = 253, IPv6_RT_HEADER_EXP2 = 254 }; /* Routing Header Types */ static const value_string routing_header_type[] = { { IPv6_RT_HEADER_SOURCE_ROUTING, "Source Route" }, { IPv6_RT_HEADER_NIMROD, "Nimrod" }, { IPv6_RT_HEADER_MOBILE_IP, "Type 2 Routing" }, { IPv6_RT_HEADER_RPL, "RPL Source Route" }, { IPv6_RT_HEADER_SEGMENT_ROUTING, "Segment Routing" }, { IPv6_RT_HEADER_COMPACT_16, "Compact Routing Header 16" }, { IPv6_RT_HEADER_COMPACT_32, "Compact Routing Header 32" }, { IPv6_RT_HEADER_EXP1, "Experiment 1" }, { IPv6_RT_HEADER_EXP2, "Experiment 2" }, { 0, NULL } }; static const value_string mpl_seed_id_len_vals[] = { { 0, "0" }, { 1, "16-bit unsigned integer" }, { 2, "64-bit unsigned integer" }, { 3, "128-bit unsigned integer" }, { 0, NULL } }; static const value_string ipv6_multicast_scope_vals[] = { { 0x0, "Reserved" }, { 0x1, "Interface-Local scope" }, { 0x2, "Link-Local scope" }, { 0x3, "Realm-Local scope" }, { 0x4, "Admin-Local scope" }, { 0x5, "Site-Local scope" }, { 0x6, "Unassigned" }, { 0x7, "Unassigned" }, { 0x8, "Organization-Local scope" }, { 0x9, "Unassigned" }, { 0xA, "Unassigned" }, { 0xB, "Unassigned" }, { 0xC, "Unassigned" }, { 0xD, "Unassigned" }, { 0xE, "Global scope" }, { 0xF, "Reserved" }, { 0, NULL } }; #define APN_ID_32BIT 1 #define APN_ID_64BIT 2 #define APN_ID_128BIT 3 static const value_string apn_id_type_strs[] = { { 0, "Invalid" }, { APN_ID_32BIT, "32-bit" }, { APN_ID_64BIT, "64-bit" }, { APN_ID_128BIT, "128-bit" }, { 0, NULL } }; static gboolean capture_ipv6(const guchar *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header) { guint8 nxt; if (!BYTES_ARE_IN_FRAME(offset, len, IPv6_HDR_SIZE)) return FALSE; capture_dissector_increment_count(cpinfo, proto_ipv6); nxt = pd[offset+6]; /* get the "next header" value */ offset += IPv6_HDR_SIZE; /* skip past the IPv6 header */ return try_capture_dissector("ip.proto", nxt, pd, offset, len, cpinfo, pseudo_header); } static gboolean capture_ipv6_exthdr(const guchar *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header) { guint8 nxt; int advance; if (!BYTES_ARE_IN_FRAME(offset, len, 2)) return FALSE; nxt = pd[offset]; switch (nxt) { case IP_PROTO_FRAGMENT: advance = IPv6_FRAGMENT_HDR_SIZE; break; default: advance = (pd[offset+1] + 1) << 3; break; } if (!BYTES_ARE_IN_FRAME(offset, len, advance)) return FALSE; offset += advance; return try_capture_dissector("ip.proto", nxt, pd, offset, len, cpinfo, pseudo_header); } static void add_geoip_info_entry(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, const ws_in6_addr *ip6, int isdst) { const mmdb_lookup_t *lookup = maxmind_db_lookup_ipv6(ip6); 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 ? IP6H_DST : IP6H_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, 16, 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, 16, lookup->city); proto_item_set_generated(item); item = proto_tree_add_string(geoip_info_tree, hf_geoip_city, tvb, addr_offset, 16, 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, 16, lookup->country); proto_item_set_generated(item); item = proto_tree_add_string(geoip_info_tree, hf_geoip_country, tvb, addr_offset, 16, 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, 16, lookup->country_iso); proto_item_set_generated(item); item = proto_tree_add_string(geoip_info_tree, hf_geoip_country_iso, tvb, addr_offset, 16, 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, 16, lookup->as_number); proto_item_set_generated(item); item = proto_tree_add_uint(geoip_info_tree, hf_geoip_as_number, tvb, addr_offset, 16, 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, 16, lookup->as_org); proto_item_set_generated(item); item = proto_tree_add_string(geoip_info_tree, hf_geoip_as_org, tvb, addr_offset, 16, 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, 16, lookup->latitude); proto_item_set_generated(item); item = proto_tree_add_double(geoip_info_tree, hf_geoip_latitude, tvb, addr_offset, 16, 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, 16, lookup->longitude); proto_item_set_generated(item); item = proto_tree_add_double(geoip_info_tree, hf_geoip_longitude, tvb, addr_offset, 16, lookup->longitude); proto_item_set_generated(item); } } static void add_geoip_info(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, gint offset, const ws_in6_addr *src, const ws_in6_addr *dst) { add_geoip_info_entry(tree, pinfo, tvb, offset, src, FALSE); add_geoip_info_entry(tree, pinfo, tvb, offset, dst, TRUE); } /* Returns TRUE if reassembled */ static gboolean ipv6_reassemble_do(tvbuff_t **tvb_ptr, gint *offset_ptr, packet_info *pinfo, proto_tree *ipv6_tree, guint32 plen, guint16 frag_off, gboolean frag_flg, guint32 frag_ident, gboolean *show_data_ptr) { fragment_head *ipfd_head; tvbuff_t *next_tvb; gboolean update_col_info = TRUE; pinfo->fragmented = TRUE; *show_data_ptr = TRUE; if (!ipv6_reassemble) { /* not reassembling */ if (frag_off == 0) { /* first fragment */ *show_data_ptr = FALSE; } return FALSE; } /* reassembling */ if (tvb_bytes_exist(*tvb_ptr, *offset_ptr, plen)) { ipfd_head = fragment_add_check(&ipv6_reassembly_table, *tvb_ptr, *offset_ptr, pinfo, frag_ident, NULL, frag_off, plen, frag_flg); next_tvb = process_reassembled_data(*tvb_ptr, *offset_ptr, pinfo, "Reassembled IPv6", ipfd_head, &ipv6_frag_items, &update_col_info, ipv6_tree); if (next_tvb) { /* Process post-fragment headers after reassembly */ *offset_ptr = 0; *tvb_ptr = next_tvb; pinfo->fragmented = FALSE; *show_data_ptr = FALSE; return TRUE; } } return FALSE; } static proto_item * _proto_tree_add_ipv6_vector_address(proto_tree *tree, packet_info *pinfo, int hfindex, tvbuff_t *tvb, gint start, gint length, const ws_in6_addr *value_ptr, int idx) { address addr; gchar *str; set_address_ipv6(&addr, value_ptr); str = address_with_resolution_to_str(pinfo->pool, &addr); return proto_tree_add_ipv6_format(tree, hfindex, tvb, start, length, value_ptr, "Address[%d]: %s", idx, str); } /* IPv6 Source Routing Header (Type 0) */ static int dissect_routing6_rt0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { struct ws_rthdr *rt = (struct ws_rthdr *)data; proto_item *ti; int offset = 0; gint idx; gint rt0_addr_count; const ws_in6_addr *addr = NULL; proto_tree_add_item(tree, hf_ipv6_routing_src_reserved, tvb, offset, 4, ENC_NA); offset += 4; if (rt->hdr.ip6r_len % 2 != 0) { expert_add_info_format(pinfo, rt->ti_len, &ei_ipv6_routing_invalid_length, "IPv6 Routing Header extension header length must not be odd"); } rt0_addr_count = rt->hdr.ip6r_len / 2; if (rt->hdr.ip6r_segleft > rt0_addr_count) { expert_add_info_format(pinfo, rt->ti_segleft, &ei_ipv6_routing_invalid_segleft, "IPv6 Type 0 Routing Header segments left field must not exceed address count (%u)", rt0_addr_count); } for (idx = 1; idx <= rt0_addr_count; idx++) { addr = tvb_get_ptr_ipv6(tvb, offset); ti = _proto_tree_add_ipv6_vector_address(tree, pinfo, hf_ipv6_routing_src_addr, tvb, offset, IPv6_ADDR_SIZE, addr, idx); offset += IPv6_ADDR_SIZE; if (in6_addr_is_multicast(addr)) { expert_add_info(pinfo, ti, &ei_ipv6_src_route_list_multicast_addr); } } if (addr != NULL && pinfo->dst.type == AT_IPv6 && rt->hdr.ip6r_segleft > 0) { alloc_address_wmem_ipv6(pinfo->pool, &pinfo->dst, addr); } expert_add_info(pinfo, rt->ti_type, &ei_ipv6_routing_deprecated); return tvb_captured_length(tvb); } /* Mobile IPv6 Routing Header (Type 2) */ static int dissect_routing6_mipv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { struct ws_rthdr *rt = (struct ws_rthdr *)data; proto_item *ti; int offset = 0; const ws_in6_addr *addr; proto_tree_add_item(tree, hf_ipv6_routing_mipv6_reserved, tvb, offset, 4, ENC_NA); offset += 4; if (rt->hdr.ip6r_len != 2) { expert_add_info_format(pinfo, rt->ti_len, &ei_ipv6_routing_invalid_length, "IPv6 Type 2 Routing Header extension header length must equal 2"); } if (rt->hdr.ip6r_segleft != 1) { expert_add_info_format(pinfo, rt->ti_segleft, &ei_ipv6_routing_invalid_segleft, "IPv6 Type 2 Routing Header segments left field must equal 1"); } addr = tvb_get_ptr_ipv6(tvb, offset); ti = _proto_tree_add_ipv6_vector_address(tree, pinfo, hf_ipv6_routing_mipv6_home_address, tvb, offset, IPv6_ADDR_SIZE, addr, 1); if (in6_addr_is_multicast(addr)) { expert_add_info(pinfo, ti, &ei_ipv6_src_route_list_multicast_addr); } if (pinfo->dst.type == AT_IPv6 && rt->hdr.ip6r_segleft > 0) { alloc_address_wmem_ipv6(pinfo->pool, &pinfo->dst, addr); } return tvb_captured_length(tvb); } /* RPL Source Routing Header (Type 3) */ static int dissect_routing6_rpl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { struct ws_rthdr *rt = (struct ws_rthdr *)data; proto_item *ti; int offset = 0; guint8 cmprI, cmprE, cmprX, pad; guint32 reserved; gint idx; gint rpl_addr_count; ws_in6_addr rpl_fulladdr; const ws_in6_addr *ip6_dst_addr, *ip6_src_addr; wmem_array_t *rpl_addr_vector = NULL; guint i; /* Must be IPv6 addresses */ if ((pinfo->dst.type != AT_IPv6) || (pinfo->src.type != AT_IPv6)) return 0; /* IPv6 destination address used for elided bytes */ ip6_dst_addr = (const ws_in6_addr *)pinfo->dst.data; /* IPv6 source address used for strict checking */ ip6_src_addr = (const ws_in6_addr *)pinfo->src.data; /* from RFC6554: Multicast addresses MUST NOT appear in the IPv6 Destination Address field */ if (in6_addr_is_multicast(ip6_dst_addr)) { expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_ipv6_dst_addr_not_multicast); } proto_tree_add_item(tree, hf_ipv6_routing_rpl_cmprI, tvb, offset, 4, ENC_BIG_ENDIAN); proto_tree_add_item(tree, hf_ipv6_routing_rpl_cmprE, tvb, offset, 4, ENC_BIG_ENDIAN); ti = proto_tree_add_item(tree, hf_ipv6_routing_rpl_pad, tvb, offset, 4, ENC_BIG_ENDIAN); cmprI = tvb_get_guint8(tvb, offset) & 0xF0; cmprE = tvb_get_guint8(tvb, offset) & 0x0F; pad = tvb_get_guint8(tvb, offset + 1) & 0xF0; /* Shift bytes over */ cmprI >>= 4; pad >>= 4; /* from RFC6554: when CmprI and CmprE are both 0, Pad MUST carry a value of 0 */ if (cmprI == 0 && cmprE == 0 && pad != 0) { expert_add_info_format(pinfo, ti, &ei_ipv6_routing_rpl_cmpri_cmpre_pad, "When cmprI equals 0 and cmprE equals 0, pad MUST equal 0 but instead was %d", pad); } ti = proto_tree_add_item(tree, hf_ipv6_routing_rpl_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); reserved = tvb_get_bits32(tvb, ((offset + 1) * 8) + 4, 20, ENC_BIG_ENDIAN); if (reserved != 0) { expert_add_info_format(pinfo, ti, &ei_ipv6_routing_rpl_reserved, "Reserved field must equal 0 but instead was %d", reserved); } /* From RFC6554: * n = (((Hdr Ext Len * 8) - Pad - (16 - CmprE)) / (16 - CmprI)) + 1 */ rpl_addr_count = 0; if (rt->hdr.ip6r_len > 0) { rpl_addr_count = (((rt->hdr.ip6r_len * 8) - pad - (16 - cmprE)) / (16 - cmprI)) + 1; } ti = proto_tree_add_int(tree, hf_ipv6_routing_rpl_addr_count, tvb, offset, 2, rpl_addr_count); proto_item_set_generated(ti); if (rpl_addr_count < 0) { /* This error should always be reported */ expert_add_info_format(pinfo, ti, &ei_ipv6_routing_rpl_addr_count_ge0, "Calculated total address count must be greater than or equal to 0, instead was %d", rpl_addr_count); } else if (rt->hdr.ip6r_segleft > (guint)rpl_addr_count) { expert_add_info_format(pinfo, rt->ti_segleft, &ei_ipv6_routing_invalid_segleft, "IPv6 RPL Routing Header segments left field must not exceed address count (%d)", rpl_addr_count); } if (rpl_addr_count > 0) { offset += 4; if (g_ipv6_rpl_srh_strict_rfc_checking) rpl_addr_vector = wmem_array_sized_new(pinfo->pool, IPv6_ADDR_SIZE, rpl_addr_count); /* We use cmprI for internal (e.g.: not last) address for how many bytes to elide, so actual bytes present = 16-CmprI */ for (idx = 1; idx <= rpl_addr_count; idx++) { if (idx == rpl_addr_count) cmprX = 16 - cmprE; else cmprX = 16 - cmprI; proto_tree_add_item(tree, hf_ipv6_routing_rpl_addr, tvb, offset, cmprX, ENC_NA); /* Display Full Address */ memcpy(&rpl_fulladdr, ip6_dst_addr, IPv6_ADDR_SIZE); tvb_memcpy(tvb, &rpl_fulladdr.bytes[16-cmprX], offset, cmprX); ti = _proto_tree_add_ipv6_vector_address(tree, pinfo, hf_ipv6_routing_rpl_fulladdr, tvb, offset, cmprX, &rpl_fulladdr, idx); proto_item_set_generated(ti); offset += cmprX; /* IPv6 Source and Destination addresses of the encapsulating datagram (MUST) not appear in the SRH*/ if (memcmp(&rpl_fulladdr, ip6_src_addr, IPv6_ADDR_SIZE) == 0) { expert_add_info(pinfo, ti, &ei_ipv6_src_route_list_src_addr); } if (memcmp(&rpl_fulladdr, ip6_dst_addr, IPv6_ADDR_SIZE) == 0) { expert_add_info(pinfo, ti, &ei_ipv6_src_route_list_dst_addr); } /* Multicast addresses MUST NOT appear in the in SRH */ if (in6_addr_is_multicast(&rpl_fulladdr)) { expert_add_info(pinfo, ti, &ei_ipv6_src_route_list_multicast_addr); } if (g_ipv6_rpl_srh_strict_rfc_checking) { /* from RFC6554: */ /* The SRH MUST NOT specify a path that visits a node more than once. */ /* To do this, we will just check the current 'addr' against the previous addresses */ for (i = 0; i < wmem_array_get_count(rpl_addr_vector); i++) { /* Compare the addresses */ if (memcmp(&rpl_fulladdr, wmem_array_index(rpl_addr_vector, i), IPv6_ADDR_SIZE) == 0) { /* Found a previous that is the same */ expert_add_info(pinfo, ti, &ei_ipv6_src_route_list_mult_inst_same_addr); break; } } wmem_array_append(rpl_addr_vector, &rpl_fulladdr, 1); } if (pinfo->dst.type == AT_IPv6 && rt->hdr.ip6r_segleft > 0) { alloc_address_wmem_ipv6(pinfo->pool, &pinfo->dst, &rpl_fulladdr); } } } return tvb_captured_length(tvb); } /* Segment Routing Header (Type 4) */ static int dissect_routing6_srh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { struct ws_rthdr *rt = (struct ws_rthdr *)data; int offset = 0; gint addr_offset; guint32 last_entry, addr_count; proto_tree_add_item_ret_uint(tree, hf_ipv6_routing_srh_last_entry, tvb, offset, 1, ENC_BIG_ENDIAN, &last_entry); addr_count = last_entry + 1; offset += 1; proto_tree_add_item(tree, hf_ipv6_routing_srh_flags, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(tree, hf_ipv6_routing_srh_tag, tvb, offset, 2, ENC_NA); offset += 2; if (rt->hdr.ip6r_segleft > addr_count) { expert_add_info_format(pinfo, rt->ti_segleft, &ei_ipv6_routing_invalid_segleft, "IPv6 Type 4 Routing Header segments left field must not exceed address count (%u)", addr_count); } if (pinfo->dst.type == AT_IPv6 && rt->hdr.ip6r_segleft > 0) { alloc_address_wmem_ipv6(pinfo->pool, &pinfo->dst, tvb_get_ptr_ipv6(tvb, offset)); } for (unsigned i = 0; i < addr_count; i++) { addr_offset = offset + i * IPv6_ADDR_SIZE; _proto_tree_add_ipv6_vector_address(tree, pinfo, hf_ipv6_routing_srh_addr, tvb, addr_offset, IPv6_ADDR_SIZE, tvb_get_ptr_ipv6(tvb, addr_offset), i); } /* TODO: dissect TLVs */ return tvb_captured_length(tvb); } /* Compact Routing Header 16 (Type 5) and Compact Routing Header 32 (Type 6). https://tools.ietf.org/html/draft-bonica-6man-comp-rtg-hdr-23. */ static int dissect_routing6_crh(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data) { int offset, minimum_crh_length; gint sid; unsigned sid_count; unsigned octets_per_sid; unsigned sids_beyond_first_word; unsigned sids_per_word; struct ws_rthdr* rt = (struct ws_rthdr*)data; gboolean is_crh16 = rt->hdr.ip6r_type == IPv6_RT_HEADER_COMPACT_16; guint8 segments_left = rt->hdr.ip6r_segleft; /* Compute the minimum CRH length measured in 8-octet units, not including the first 8 octets */ minimum_crh_length = -1; switch (rt->hdr.ip6r_type) { case IPv6_RT_HEADER_COMPACT_16: octets_per_sid = 2; sids_per_word = 4; sid_count = rt->hdr.ip6r_len * 4 + 2; if (segments_left <= 2) minimum_crh_length = 0; sids_beyond_first_word = segments_left - 2; break; case IPv6_RT_HEADER_COMPACT_32: octets_per_sid = 4; sids_per_word = 2; sid_count = rt->hdr.ip6r_len * 2 + 1; if (segments_left <= 1) minimum_crh_length = 0; sids_beyond_first_word = segments_left - 1; break; default: DISSECTOR_ASSERT_NOT_REACHED(); } if (minimum_crh_length) { minimum_crh_length = sids_beyond_first_word / sids_per_word; if (sids_beyond_first_word % sids_per_word) minimum_crh_length++; } if (minimum_crh_length > rt->hdr.ip6r_len) { expert_add_info_format(pinfo, rt->ti_len, &ei_ipv6_routing_invalid_length, "IPv6 Compact Routing Header minimum length must not exceed header length (%u)", rt->hdr.ip6r_len); } offset = 0; if (is_crh16) { proto_item* current_sid_item = proto_tree_add_item(tree, hf_ipv6_routing_crh16_current_sid, tvb, offset + (octets_per_sid * segments_left), octets_per_sid, ENC_BIG_ENDIAN); proto_item_set_generated(current_sid_item); } else { proto_item* current_sid_item = proto_tree_add_item(tree, hf_ipv6_routing_crh32_current_sid, tvb, offset + (octets_per_sid * segments_left), octets_per_sid, ENC_BIG_ENDIAN); proto_item_set_generated(current_sid_item); } sid = is_crh16 ? tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN) : tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN); proto_tree* segment_ids = proto_tree_add_subtree(tree, tvb, 0, -1, 0, NULL, "Segment Identifiers"); for (unsigned i = 0; i < sid_count && sid; i++) { if (is_crh16) { proto_tree_add_uint_format(segment_ids, hf_ipv6_routing_crh16_segment_id, tvb, offset, octets_per_sid, sid, "SID[%d] = %d", i, sid); } else { proto_tree_add_uint_format(segment_ids, hf_ipv6_routing_crh32_segment_id, tvb, offset, octets_per_sid, sid, "SID[%d] = %d", i, sid); } offset += octets_per_sid; sid = is_crh16 ? tvb_get_guint16(tvb, offset, ENC_BIG_ENDIAN) : tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN); } return tvb_captured_length(tvb); } /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len | Routing Type | Segments Left | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | . . . type-specific data . . . | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static int dissect_routing6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { struct ws_rthdr rt; guint nxt, hdr_len, total_len; proto_tree *rt_tree, *root_tree; proto_item *pi, *ti, *ti_hdr_len, *ti_type, *ti_segs; int offset = 0; tvbuff_t *next_tvb; int type, type_len; dissector_handle_t type_dissector; col_append_sep_str(pinfo->cinfo, COL_INFO, " , ", "IPv6 routing"); root_tree = p_ipv6_pinfo_select_root(pinfo, tree); pi = proto_tree_add_item(root_tree, proto_ipv6_routing, tvb, offset, -1, ENC_NA); rt_tree = proto_item_add_subtree(pi, ett_ipv6_routing_proto); proto_tree_add_item(rt_tree, hf_ipv6_routing_nxt, tvb, offset, 1, ENC_BIG_ENDIAN); nxt = tvb_get_guint8(tvb, offset); offset += 1; ti_hdr_len = proto_tree_add_item(rt_tree, hf_ipv6_routing_len, tvb, offset, 1, ENC_BIG_ENDIAN); hdr_len = tvb_get_guint8(tvb, offset); /* Hdr Ext Len 8-bit unsigned integer. Length of the Routing header in 8-octet units, not including the first 8 octets. */ total_len = (hdr_len + 1) * 8; type_len = total_len - 4; proto_item_set_len(pi, total_len); ti = proto_tree_add_uint(rt_tree, hf_ipv6_routing_len_oct, tvb, offset, 1, total_len); proto_item_set_generated(ti); if (ipv6_exthdr_hide_len_oct_field) { proto_item_set_hidden(ti); proto_item_append_text(ti_hdr_len, " (%d bytes)", total_len); } p_ipv6_pinfo_add_len(pinfo, total_len); offset += 1; ti_type = proto_tree_add_item(rt_tree, hf_ipv6_routing_type, tvb, offset, 1, ENC_BIG_ENDIAN); type = tvb_get_guint8(tvb, offset); proto_item_append_text(pi, " (%s)", val_to_str(type, routing_header_type, "Unknown type %u")); offset += 1; ti_segs = proto_tree_add_item(rt_tree, hf_ipv6_routing_segleft, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; type_dissector = dissector_get_uint_handle(ipv6_routing_dissector_table, type); if (type_dissector != NULL) { tvb_memcpy(tvb, &(rt.hdr), 0, 4); rt.ti_len = ti_hdr_len; rt.ti_type = ti_type; rt.ti_segleft = ti_segs; call_dissector_with_data(type_dissector, tvb_new_subset_length(tvb, offset, type_len), pinfo, rt_tree, &rt); } else { /* Unknown Routing Header Type */ ti = proto_tree_add_item(rt_tree, hf_ipv6_routing_unknown_data, tvb, offset, type_len, ENC_NA); expert_add_info(pinfo, ti, &ei_ipv6_routing_undecoded); } p_add_ipv6_nxt(pinfo, nxt); next_tvb = tvb_new_subset_remaining(tvb, total_len); ipv6_dissect_next(nxt, next_tvb, pinfo, tree, (ws_ip6 *)data); return tvb_captured_length(tvb); } static int dissect_fraghdr(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *pi, *ti; proto_tree *frag_tree, *root_tree; guint8 nxt; guint16 offlg; guint16 frag_off; gboolean frag_flg; guint32 frag_ident; gint offset = 0; ipv6_pinfo_t *ipv6_pinfo; gboolean show_data = FALSE; gboolean reassembled; tvbuff_t *next_tvb; nxt = tvb_get_guint8(tvb, offset); offlg = tvb_get_ntohs(tvb, offset + 2); frag_off = offlg & IP6F_OFF_MASK; /* offset in bytes */ frag_flg = offlg & IP6F_MORE_FRAG; frag_ident = tvb_get_ntohl(tvb, offset + 4); col_add_fstr(pinfo->cinfo, COL_INFO, "IPv6 fragment (off=%u more=%s ident=0x%08x nxt=%u)", frag_off, frag_flg ? "y" : "n", frag_ident, nxt); root_tree = p_ipv6_pinfo_select_root(pinfo, tree); ipv6_pinfo = p_ipv6_pinfo_add_len(pinfo, IPv6_FRAGMENT_HDR_SIZE); /* IPv6 Fragmentation Header has fixed length of 8 bytes */ pi = proto_tree_add_item(root_tree, proto_ipv6_fraghdr, tvb, offset, IPv6_FRAGMENT_HDR_SIZE, ENC_NA); if (ipv6_pinfo != NULL && ipv6_pinfo->jumbo_plen != 0) { expert_add_info(pinfo, pi, &ei_ipv6_opt_jumbo_fragment); } frag_tree = proto_item_add_subtree(pi, ett_ipv6_fraghdr_proto); proto_tree_add_item(frag_tree, hf_ipv6_fraghdr_nxt, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(frag_tree, hf_ipv6_fraghdr_reserved_octet, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; ti = proto_tree_add_item(frag_tree, hf_ipv6_fraghdr_offset, tvb, offset, 2, ENC_BIG_ENDIAN); proto_item_append_text(ti, " (%d bytes)", frag_off); proto_tree_add_item(frag_tree, hf_ipv6_fraghdr_reserved_bits, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(frag_tree, hf_ipv6_fraghdr_more, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(frag_tree, hf_ipv6_fraghdr_ident, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; if (ipv6_pinfo != NULL && ipv6_pinfo->frag_plen > 0) { if ((frag_off != 0) || frag_flg) { reassembled = ipv6_reassemble_do(&tvb, &offset, pinfo, root_tree, ipv6_pinfo->frag_plen, frag_off, frag_flg, frag_ident, &show_data); if (show_data) { next_tvb = tvb_new_subset_remaining(tvb, offset); call_data_dissector(next_tvb, pinfo, tree); return tvb_captured_length(tvb); } if (reassembled) { ipv6_pinfo->frag_plen = 0; next_tvb = tvb_new_subset_remaining(tvb, offset); ipv6_dissect_next(nxt, next_tvb, pinfo, tree, (ws_ip6 *)data); return tvb_captured_length(tvb); } } } p_add_ipv6_nxt(pinfo, nxt); next_tvb = tvb_new_subset_remaining(tvb, offset); ipv6_dissect_next(nxt, next_tvb, pinfo, tree, (ws_ip6 *)data); return tvb_captured_length(tvb); } struct opt_proto_item { proto_item *type, *len; }; /* * Jumbo Payload Option * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option Type | Opt Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Jumbo Payload Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_jumbo(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { proto_item *pi = proto_tree_get_parent(opt_tree); proto_item *ti; guint32 jumbo_plen = 0; ipv6_pinfo_t *ipv6_pinfo = p_get_ipv6_pinfo(pinfo); if (opt_len != 4) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "Jumbo Payload: Invalid length (%u bytes)", opt_len); } ti = proto_tree_add_item_ret_uint(opt_tree, hf_ipv6_opt_jumbo, tvb, offset, 4, ENC_BIG_ENDIAN, &jumbo_plen); offset += 4; if (ipv6_pinfo != NULL && ipv6_pinfo->ip6_plen != 0) { expert_add_info(pinfo, pi, &ei_ipv6_opt_jumbo_prohibited); } if (jumbo_plen < 65536) { expert_add_info(pinfo, ti, &ei_ipv6_opt_jumbo_truncated); } return offset; } /* * RPL Option * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option Type | Opt Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |O|R|F|0|0|0|0|0| RPLInstanceID | SenderRank | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | (sub-TLVs) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_rpl(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { static int * const rpl_flags[] = { &hf_ipv6_opt_rpl_flag_o, &hf_ipv6_opt_rpl_flag_r, &hf_ipv6_opt_rpl_flag_f, &hf_ipv6_opt_rpl_flag_rsv, NULL }; if (opt_len < 4) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "RPL Option: Invalid length (%u bytes)", opt_len); } proto_tree_add_bitmask(opt_tree, tvb, offset, hf_ipv6_opt_rpl_flag, ett_ipv6_opt_rpl, rpl_flags, ENC_NA); offset += 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_rpl_instance_id, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_rpl_senderrank, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* TODO: Add dissection of sub-TLVs */ return offset; } /* * Tunnel Encapsulation Limit Option * Option Type Opt Data Len Opt Data Len 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0 0 0 0 0 1 0 0| 1 | Tun Encap Lim | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_tel(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { if (opt_len != 1) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "Tunnel Encapsulation Limit: Invalid length (%u bytes)", opt_len); } proto_tree_add_item(opt_tree, hf_ipv6_opt_tel, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; return offset; } /* * IPv6 Minimum Path MTU Hop by Hop Option * Option Option Option Type Data Len Data +--------+--------+--------+--------+---------+-------+-+ |BBCTTTTT|00000100| Min-PMTU | Rtn-PMTU |R| +--------+--------+--------+--------+---------+-------+-+ Option Type: BB 00 Skip over this option and continue processing. C 1 Option data can change en route to the packet's final destination. TTTTT 10000 Option Type assigned from IANA [IANA-HBH]. Length: 4 The size of the each value field in Option Data field supports Path MTU values from 0 to 65,535 octets. Min-PMTU: n 16-bits. The minimum PMTU in octets, reflecting the smallest link MTU that the packet experienced across the path. This is called the Reported PMTU. A value less than the IPv6 minimum link MTU [RFC8200] should be ignored. Rtn-PMTU: n 15-bits. The returned minimum PMTU, carrying the 15 most significant bits of the latest received Min-PMTU field. The value zero means that no Reported MTU is being returned. R n 1-bit. R-Flag. Set by the source to signal that the destination should include the received Reported PMTU in Rtn-PMTU field. [IANA-HBH] "Destination Options and Hop-by-Hop Options", */ static gint dissect_opt_pmtu(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { guint16 val; if (opt_len != 4) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "PMTU Option: Invalid Length (%u bytes)", opt_len); } proto_tree_add_item(opt_tree, hf_ipv6_opt_pmtu_min, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; val = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(opt_tree, hf_ipv6_opt_pmtu_rtn, tvb, offset, 2, val & 0xFFFE); offset += 1; proto_tree_add_boolean(opt_tree, hf_ipv6_opt_pmtu_rtn_flag, tvb, offset, 1, val & 0x0001); offset += 1; return offset; } /* * IETF APN6 * * Application-Aware IPv6 Networking (APN6) * * https://datatracker.ietf.org/wg/apn/about/ * https://datatracker.ietf.org/doc/draft-li-apn-header/ * https://datatracker.ietf.org/doc/draft-li-apn-ipv6-encap/ * * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | APN-ID-Type | Flags | APN-Para-Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | APN-ID | | (32-bit/64-bit/128-bit) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ static gint dissect_opt_apn6(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { if (opt_len < 8) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "APN6 Option: Invalid Length (%u bytes) for basic APN header and shortest APN ID(32-bit)", opt_len); } guint32 parsed_offset = 0; // offset is for DOH header; parsed_offset is for APN option. proto_tree *sub_tree = proto_tree_add_subtree(opt_tree, tvb, offset, opt_len, 0, NULL, "APN Header"); guint8 apn_id_type = tvb_get_guint8(tvb, offset); proto_item *apn_id_type_i = proto_tree_add_item(sub_tree, hf_ipv6_opt_apn_id_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; parsed_offset++; if (apn_id_type < APN_ID_32BIT || apn_id_type > APN_ID_128BIT) { expert_add_info_format(pinfo, apn_id_type_i, &ei_ipv6_opt_apn_invalid_id_type, "APN6 Option: Invalid APN ID Type (%u)", apn_id_type); } proto_tree_add_item(sub_tree, hf_ipv6_opt_apn_flags, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; parsed_offset++; proto_tree_add_item(sub_tree, hf_ipv6_opt_apn_param_type, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; parsed_offset += 2; if (apn_id_type >= APN_ID_32BIT) { proto_tree_add_item(sub_tree, hf_ipv6_opt_apn_id_part1, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; parsed_offset += 4; } if (apn_id_type >= APN_ID_64BIT) { if (opt_len - parsed_offset < 4) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "APN6 Option: Invalid Length (%u bytes) for 64-bit APN ID, parsed offset %u", opt_len, parsed_offset); } proto_tree_add_item(sub_tree, hf_ipv6_opt_apn_id_part2, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; parsed_offset += 4; } if (apn_id_type >= APN_ID_128BIT) { if (opt_len - parsed_offset < 8) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "APN6 Option: Invalid Length (%u bytes) for 128-bit APN ID, parsed offset %u", opt_len, parsed_offset); } proto_tree_add_item(sub_tree, hf_ipv6_opt_apn_id_part3, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(sub_tree, hf_ipv6_opt_apn_id_part4, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } return offset; } /* * IPv6 Router Alert Option * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0 0 0|0 0 1 0 1|0 0 0 0 0 0 1 0| Value (2 octets) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ length = 2 */ static gint dissect_opt_rtalert(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { if (opt_len != 2) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "Router alert: Invalid Length (%u bytes)", opt_len); } proto_tree_add_item(opt_tree, hf_ipv6_opt_rtalert, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; return offset; } /* * Quick-Start Option for IPv6 * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option | Length=6 | Func. | Rate | Not Used | | | | 1000 | Report| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | QS Nonce | R | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_quickstart(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len, ws_ip6 *iph) { proto_item *pi = proto_tree_get_parent(opt_tree); proto_item *ti; guint8 command, function, rate; guint32 qs_ttl = 0; if (opt_len != 6) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "Quick-Start: Invalid Length (%u bytes)", opt_len); } command = tvb_get_guint8(tvb, offset); function = command >> 4; rate = command & QS_RATE_MASK; proto_tree_add_item(opt_tree, hf_ipv6_opt_qs_func, tvb, offset, 1, ENC_BIG_ENDIAN); switch (function) { case QS_RATE_REQUEST: proto_tree_add_item(opt_tree, hf_ipv6_opt_qs_rate, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item_ret_uint(opt_tree, hf_ipv6_opt_qs_ttl, tvb, offset, 1, ENC_BIG_ENDIAN, &qs_ttl); proto_item_append_text(pi, ", %s, QS TTL %u", val_to_str_ext(rate, &qs_rate_vals_ext, "Unknown (%u)"), qs_ttl); if (iph != NULL) { guint8 ttl_diff; ttl_diff = (iph->ip6_hop - qs_ttl) % 256; ti = proto_tree_add_uint(opt_tree, hf_ipv6_opt_qs_ttl_diff, tvb, offset, 1, ttl_diff); proto_item_set_generated(ti); proto_item_append_text(pi, ", QS TTL diff %u", ttl_diff); } offset += 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_qs_nonce, tvb, offset, 4, ENC_BIG_ENDIAN); proto_tree_add_item(opt_tree, hf_ipv6_opt_qs_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; break; case QS_RATE_REPORT: proto_tree_add_item(opt_tree, hf_ipv6_opt_qs_rate, tvb, offset, 1, ENC_BIG_ENDIAN); proto_item_append_text(pi, ", %s", val_to_str_ext(rate, &qs_rate_vals_ext, "Unknown (%u)")); offset += 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_qs_unused, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_qs_nonce, tvb, offset, 4, ENC_BIG_ENDIAN); proto_tree_add_item(opt_tree, hf_ipv6_opt_qs_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; break; default: break; } return offset; } static const value_string ipv6_ioam_opt_types[] = { { IP6IOAM_PRE_TRACE, "Pre-allocated Trace" }, { IP6IOAM_INC_TRACE, "Incremental Trace" }, { IP6IOAM_POT, "Proof of Transit" }, { IP6IOAM_E2E, "Edge to Edge" }, { 0, NULL} }; static gint dissect_opt_ioam_trace_node(tvbuff_t *tvb, gint offset, proto_tree *opt_tree, guint32 trace_type) { proto_tree* sub_tree; if (trace_type & IP6IOAM_TRACE_MASK_BIT0) { sub_tree = proto_tree_add_subtree(opt_tree, tvb, offset, 4, 0, NULL, "Hop_Lim and Node ID (short)"); proto_tree_add_item(sub_tree, hf_ipv6_opt_ioam_trace_node_hlim, tvb, offset, 1, ENC_NA); proto_tree_add_item(sub_tree, hf_ipv6_opt_ioam_trace_node_id, tvb, offset + 1, 3, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT1) { sub_tree = proto_tree_add_subtree(opt_tree, tvb, offset, 4, 0, NULL, "Ingress and Egress IDs (short)"); proto_tree_add_item(sub_tree, hf_ipv6_opt_ioam_trace_node_iif, tvb, offset, 2, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_ipv6_opt_ioam_trace_node_eif, tvb, offset + 2, 2, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT2) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_tss, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT3) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_tsf, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT4) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_trdelay, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT5) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_nsdata, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT6) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_qdepth, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT7) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_csum, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT8) { sub_tree = proto_tree_add_subtree(opt_tree, tvb, offset, 8, 0, NULL, "Hop_Lim and Node ID (wide)"); proto_tree_add_item(sub_tree, hf_ipv6_opt_ioam_trace_node_hlim, tvb, offset, 1, ENC_NA); proto_tree_add_item(sub_tree, hf_ipv6_opt_ioam_trace_node_id_wide, tvb, offset + 1, 7, ENC_BIG_ENDIAN); offset += 8; } if (trace_type & IP6IOAM_TRACE_MASK_BIT9) { sub_tree = proto_tree_add_subtree(opt_tree, tvb, offset, 8, 0, NULL, "Ingress and Egress IDs (wide)"); proto_tree_add_item(sub_tree, hf_ipv6_opt_ioam_trace_node_iif_wide, tvb, offset, 4, ENC_BIG_ENDIAN); proto_tree_add_item(sub_tree, hf_ipv6_opt_ioam_trace_node_eif_wide, tvb, offset + 4, 4, ENC_BIG_ENDIAN); offset += 8; } if (trace_type & IP6IOAM_TRACE_MASK_BIT10) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_nsdata_wide, tvb, offset, 8, ENC_BIG_ENDIAN); offset += 8; } if (trace_type & IP6IOAM_TRACE_MASK_BIT11) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_bufoccup, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT12) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT13) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT14) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT15) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT16) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT17) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT18) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT19) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT20) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } if (trace_type & IP6IOAM_TRACE_MASK_BIT21) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_node_undefined, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; } return offset; } /* * IOAM Trace Option Header * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Namespace-ID | NodeLen | Flags | RemainingLen| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | IOAM-Trace-Type | Reserved | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<-+ | | | | node data list [0] | | | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ D | | a | node data list [1] | t | | a +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~ ........ ~ S +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ p | | a | node data list [n-1] | c | | e +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | | | node data list [n] | | | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<-+ */ static gint dissect_opt_ioam_trace(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { proto_item *ti; guint32 trace_type, oss_scid; guint16 len; guint8 remlen, nodelen, oss_len, i = 0; gint new_offset; static int * const ioam_trace_flags[] = { &hf_ipv6_opt_ioam_trace_flag_o, &hf_ipv6_opt_ioam_trace_flag_l, &hf_ipv6_opt_ioam_trace_flag_a, &hf_ipv6_opt_ioam_trace_flag_rsv, NULL }; static int * const ioam_trace_types[] = { &hf_ipv6_opt_ioam_trace_type_bit0, &hf_ipv6_opt_ioam_trace_type_bit1, &hf_ipv6_opt_ioam_trace_type_bit2, &hf_ipv6_opt_ioam_trace_type_bit3, &hf_ipv6_opt_ioam_trace_type_bit4, &hf_ipv6_opt_ioam_trace_type_bit5, &hf_ipv6_opt_ioam_trace_type_bit6, &hf_ipv6_opt_ioam_trace_type_bit7, &hf_ipv6_opt_ioam_trace_type_bit8, &hf_ipv6_opt_ioam_trace_type_bit9, &hf_ipv6_opt_ioam_trace_type_bit10, &hf_ipv6_opt_ioam_trace_type_bit11, &hf_ipv6_opt_ioam_trace_type_undef, &hf_ipv6_opt_ioam_trace_type_bit22, &hf_ipv6_opt_ioam_trace_type_rsv, NULL }; if (opt_len < 10) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "IOAM Option: Invalid length (%u bytes)", opt_len); } proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_ns, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; nodelen = tvb_get_bits8(tvb, offset * 8, 5); ti = proto_tree_add_bits_item(opt_tree, hf_ipv6_opt_ioam_trace_nodelen, tvb, offset * 8, 5, ENC_BIG_ENDIAN); if (!nodelen) expert_add_info(pinfo, ti, &ei_ipv6_opt_ioam_invalid_nodelen); proto_tree_add_bitmask(opt_tree, tvb, offset, hf_ipv6_opt_ioam_trace_flags, ett_ipv6_opt_ioam_trace_flags, ioam_trace_flags, ENC_NA); remlen = tvb_get_bits8(tvb, offset * 8 + 9, 7); ti = proto_tree_add_bits_item(opt_tree, hf_ipv6_opt_ioam_trace_remlen, tvb, offset * 8 + 9, 7, ENC_BIG_ENDIAN); if (remlen * 4 > opt_len - 10) { expert_add_info_format(pinfo, ti, &ei_ipv6_opt_ioam_invalid_remlen, "IOAM RemLen: Invalid length (%u bytes)", remlen * 4); } offset += 2; trace_type = tvb_get_bits32(tvb, offset * 8, 24, ENC_BIG_ENDIAN); ti = proto_tree_add_bitmask(opt_tree, tvb, offset, hf_ipv6_opt_ioam_trace_type, ett_ipv6_opt_ioam_trace_types, ioam_trace_types, ENC_BIG_ENDIAN); proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_trace_rsv, tvb, offset + 3, 1, ENC_NA); offset += 4; /* node data list parsing starts here */ if (!nodelen || remlen * 4 > opt_len - 10) return offset; proto_tree* trace_tree = proto_tree_add_subtree(opt_tree, tvb, offset, opt_len - 10, 0, NULL, "Trace Data"); if (remlen) { proto_tree_add_item(trace_tree, hf_ipv6_opt_ioam_trace_free_space, tvb, offset, remlen * 4, ENC_NA); offset += remlen * 4; } len = opt_len - 10 - remlen * 4; while (len && len >= nodelen * 4) { proto_tree* node_tree = proto_tree_add_subtree_format(trace_tree, tvb, offset, nodelen * 4, 0, NULL, "Node %u", ++i); new_offset = dissect_opt_ioam_trace_node(tvb, offset, node_tree, trace_type); if (new_offset - offset != nodelen * 4) { expert_add_info(pinfo, ti, &ei_ipv6_opt_ioam_invalid_trace_type); return offset; } offset = new_offset; len -= nodelen * 4; /* Opaque State Snapshot */ if (trace_type & IP6IOAM_TRACE_MASK_BIT22) { if (len < 4) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "IOAM Option: Invalid length (%u bytes)", opt_len); return offset; } oss_len = tvb_get_guint8(tvb, offset); proto_tree* oss_tree = proto_tree_add_subtree(node_tree, tvb, offset, (oss_len + 1) * 4, 0, NULL, "Opaque State Snapshot"); proto_tree_add_item(oss_tree, hf_ipv6_opt_ioam_trace_node_oss_len, tvb, offset, 1, ENC_NA); proto_tree_add_item_ret_uint(oss_tree, hf_ipv6_opt_ioam_trace_node_oss_scid, tvb, offset + 1, 3, ENC_BIG_ENDIAN, &oss_scid); offset += 4; len -= 4; if (len < oss_len * 4) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "IOAM Option: Invalid length (%u bytes)", opt_len); return offset; } if (oss_len > 0) { proto_tree_add_item(oss_tree, hf_ipv6_opt_ioam_trace_node_oss_data, tvb, offset, oss_len * 4, ENC_NA); len -= oss_len * 4; offset += oss_len * 4; } } } if (len) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "IOAM Option: Invalid length (%u bytes)", opt_len); } return offset; } /* * IOAM Option Header * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option Type | Opt Data Len | Reserved | IOAM Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_ioam(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { guint32 opt_type; if (opt_len < 2) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "IOAM Option: Invalid length (%u bytes)", opt_len); } proto_tree_add_item(opt_tree, hf_ipv6_opt_ioam_rsv, tvb, offset, 1, ENC_NA); proto_tree_add_item_ret_uint(opt_tree, hf_ipv6_opt_ioam_opt_type, tvb, offset + 1, 1, ENC_NA, &opt_type); offset += 2; proto_tree* opt_type_tree = proto_tree_add_subtree(opt_tree, tvb, offset, opt_len - 2, 0, NULL, val_to_str_const(opt_type, ipv6_ioam_opt_types, "Unknown Option-Type")); switch (opt_type) { case IP6IOAM_PRE_TRACE: case IP6IOAM_INC_TRACE: offset = dissect_opt_ioam_trace(tvb, offset, pinfo, opt_type_tree, opt_ti, opt_len); break; case IP6IOAM_POT: break; case IP6IOAM_E2E: break; } return offset; } /* * Tunnel Payload Forwarding Option for IPv6 * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option Type | Option Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TPF Information | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_tpf(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { if (opt_len != 4) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "TPF: Invalid Length (%u bytes)", opt_len); } proto_tree_add_item(opt_tree, hf_ipv6_opt_tpf_information, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; return offset; } /* ------------------------------------------------------------ | Next Header | Hdr Ext Len | Option Type | Option Length| +-------------+---------------+-------------+--------------+ | CALIPSO Domain of Interpretation | +-------------+---------------+-------------+--------------+ | Cmpt Length | Sens Level | Checksum (CRC-16) | +-------------+---------------+-------------+--------------+ | Compartment Bitmap (Optional; variable length) | +-------------+---------------+-------------+--------------+ */ static gint dissect_opt_calipso(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { guint32 cmpt_length = 0; if (opt_len < 8) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "CALIPSO: Invalid Length (%u bytes)", opt_len); } proto_tree_add_item(opt_tree, hf_ipv6_opt_calipso_doi, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item_ret_uint(opt_tree, hf_ipv6_opt_calipso_cmpt_length, tvb, offset, 1, ENC_BIG_ENDIAN, &cmpt_length); offset += 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_calipso_sens_level, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_checksum(opt_tree, tvb, offset, hf_ipv6_opt_calipso_checksum, -1, NULL, pinfo, 0, ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS); offset += 2; proto_tree_add_item(opt_tree, hf_ipv6_opt_calipso_cmpt_bitmap, tvb, offset, cmpt_length*4, ENC_NA); offset += cmpt_length*4; return offset; } /* * IPv6 SMF_DPD Option Header * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... |0|0|0| 01000 | Opt. Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|TidTy| TidLen| TaggerId (optional) ... | +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | Identifier ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figure 3: IPv6 SMF_DPD Option Header in I-DPD mode 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... |0|0|0| OptType | Opt. Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| Hash Assist Value (HAV) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figure 4: IPv6 SMF_DPD Option Header in H-DPD Mode */ static gint dissect_opt_smf_dpd(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *opt_tree, struct opt_proto_item *opt_ti _U_, guint8 opt_len) { guint8 hash_tid; guint8 tid_len; gint ident_len; proto_tree_add_item(opt_tree, hf_ipv6_opt_smf_dpd_hash_bit, tvb, offset, 1, ENC_BIG_ENDIAN); hash_tid = tvb_get_guint8(tvb, offset); if (hash_tid & 0x80) { /* H-DPD Mode */ proto_tree_add_item(opt_tree, hf_ipv6_opt_smf_dpd_hav, tvb, offset, opt_len, ENC_NA); return offset + opt_len; } /* I-DPD Mode */ proto_tree_add_item(opt_tree, hf_ipv6_opt_smf_dpd_tid_type, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(opt_tree, hf_ipv6_opt_smf_dpd_tid_len, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; ident_len = opt_len - 1; if (hash_tid & 0x70) { tid_len = (hash_tid & 0x0f) + 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_smf_dpd_tagger_id, tvb, offset, tid_len, ENC_NA); offset += tid_len; ident_len -= tid_len; } if (ident_len > 0) { proto_tree_add_item(opt_tree, hf_ipv6_opt_smf_dpd_ident, tvb, offset, ident_len, ENC_NA); offset += ident_len; } return offset; } /* * Performance and Diagnostic Metrics Destination Option (ietf-ippm-6man-pdm-option-13) * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option Type | Option Length | ScaleDTLR | ScaleDTLS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | PSN This Packet | PSN Last Received | |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Delta Time Last Received | Delta Time Last Sent | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_pdm(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *opt_tree, struct opt_proto_item *opt_ti _U_, guint8 opt_len) { if (opt_len != 10) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "PDM: Invalid length (%u bytes)", opt_len); } proto_tree_add_item(opt_tree, hf_ipv6_opt_pdm_scale_dtlr, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_pdm_scale_dtls, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_pdm_psn_this_pkt, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(opt_tree, hf_ipv6_opt_pdm_psn_last_recv, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(opt_tree, hf_ipv6_opt_pdm_delta_last_recv, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(opt_tree, hf_ipv6_opt_pdm_delta_last_sent, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; return offset; } /* * Home Address Option * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option Type | Option Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Home Address + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_home_address(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { if (opt_len != 16) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "Home Address: Invalid length (%u bytes)", opt_len); } proto_tree_add_item(opt_tree, hf_ipv6_opt_mipv6_home_address, tvb, offset, IPv6_ADDR_SIZE, ENC_NA); alloc_address_tvb_ipv6(pinfo->pool, &pinfo->src, tvb, offset); offset += IPv6_ADDR_SIZE; return offset; } /* * ILNP Nonce Option * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len | Option Type | Option Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ / Nonce Value / +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_ilnp_nonce(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *opt_tree, struct opt_proto_item *opt_ti _U_, guint8 opt_len) { proto_tree_add_item(opt_tree, hf_ipv6_opt_ilnp_nonce, tvb, offset, opt_len, ENC_NA); offset += opt_len; return offset; } /* * Line-Identification Option * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option Type | Option Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | LineIDLen | Line ID... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_lio(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *opt_tree, struct opt_proto_item *opt_ti _U_, guint8 opt_len) { guint32 lid_len = 0; proto_tree_add_item_ret_uint(opt_tree, hf_ipv6_opt_lio_len, tvb, offset, 1, ENC_BIG_ENDIAN, &lid_len); offset += 1; if (lid_len + 1 > opt_len) { /* XXX Add expert info */ lid_len = opt_len - 1; } proto_tree_add_item(opt_tree, hf_ipv6_opt_lio_id, tvb, offset, lid_len, ENC_BIG_ENDIAN|ENC_ASCII); offset += lid_len; return offset; } /* * MPL Option * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Option Type | Opt Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | S |M|V| rsv | sequence | seed-id (optional) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_mpl(tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *opt_tree, struct opt_proto_item *opt_ti _U_, guint8 opt_len _U_) { static int * const mpl_flags[] = { &hf_ipv6_opt_mpl_flag_s, &hf_ipv6_opt_mpl_flag_m, &hf_ipv6_opt_mpl_flag_v, &hf_ipv6_opt_mpl_flag_rsv, NULL }; static const guint8 seed_id_len_arr[4] = {0, 2, 8, 16}; guint8 seed_id_len; proto_tree_add_bitmask(opt_tree, tvb, offset, hf_ipv6_opt_mpl_flag, ett_ipv6_opt_mpl, mpl_flags, ENC_NA); seed_id_len = seed_id_len_arr[tvb_get_guint8(tvb, offset) >> 6]; offset +=1; proto_tree_add_item(opt_tree, hf_ipv6_opt_mpl_sequence, tvb, offset, 1, ENC_NA); offset +=1; if (seed_id_len > 0) { proto_tree_add_item(opt_tree, hf_ipv6_opt_mpl_seed_id, tvb, offset, seed_id_len, ENC_NA); offset += seed_id_len; } else { expert_add_info(pinfo, opt_ti->type, &ei_ipv6_opt_mpl_ipv6_src_seed_id); } return offset; } /* * IPv6 DFF Header * 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Header | Hdr Ext Len | OptTypeDFF | OptDataLenDFF | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |VER|D|R|0|0|0|0| Sequence Number | Pad1 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static gint dissect_opt_dff(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti, guint8 opt_len) { static int * const dff_flags[] = { &hf_ipv6_opt_dff_flag_ver, &hf_ipv6_opt_dff_flag_dup, &hf_ipv6_opt_dff_flag_ret, &hf_ipv6_opt_dff_flag_rsv, NULL }; /* Option length is 3 octets */ /* http://www.rfc-editor.org/errata_search.php?eid=3937 */ if (opt_len != 3) { expert_add_info_format(pinfo, opt_ti->len, &ei_ipv6_opt_invalid_len, "IPv6 DFF: Invalid length (%u bytes)", opt_len); } proto_tree_add_bitmask(opt_tree, tvb, offset, hf_ipv6_opt_dff_flags, ett_ipv6_opt_dff_flags, dff_flags, ENC_NA); offset += 1; proto_tree_add_item(opt_tree, hf_ipv6_opt_dff_seqnum, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; return offset; } static gint dissect_opt_unknown(tvbuff_t *tvb, gint offset, packet_info *pinfo, proto_tree *opt_tree, struct opt_proto_item *opt_ti _U_, guint8 opt_len) { proto_item *ti; ti = proto_tree_add_item(opt_tree, hf_ipv6_opt_unknown, tvb, offset, opt_len, ENC_NA); expert_add_info(pinfo, ti, &ei_ipv6_opt_unknown_data); return offset + opt_len; } static int dissect_opts(tvbuff_t *tvb, int offset, proto_tree *tree, packet_info *pinfo, ws_ip6 *iph, const int exthdr_proto) { gint len, offset_end; guint8 nxt; proto_tree *exthdr_tree, *opt_tree, *opt_type_tree, *root_tree; proto_item *pi, *ti, *ti_len; int hf_exthdr_item_nxt, hf_exthdr_item_len, hf_exthdr_item_len_oct; int ett_exthdr_proto; guint8 opt_type, opt_len, opt_start; gint opt_hdr_type; const gchar *opt_name; gboolean hopopts; struct opt_proto_item opt_ti; tvbuff_t *next_tvb; hopopts = (exthdr_proto == proto_ipv6_hopopts); nxt = tvb_get_guint8(tvb, offset); len = (tvb_get_guint8(tvb, offset + 1) + 1) << 3; offset_end = offset + len; root_tree = p_ipv6_pinfo_select_root(pinfo, tree); p_ipv6_pinfo_add_len(pinfo, len); /* !!! specify length */ ti = proto_tree_add_item(root_tree, exthdr_proto, tvb, offset, len, ENC_NA); if (hopopts && ipv6_previous_layer_id(pinfo) != proto_ipv6) { /* IPv6 Hop-by-Hop must appear immediately after IPv6 header (RFC 2460) */ expert_add_info(pinfo, ti, &ei_ipv6_hopopts_not_first); } if (exthdr_proto == proto_ipv6_hopopts) { hf_exthdr_item_nxt = hf_ipv6_hopopts_nxt; hf_exthdr_item_len = hf_ipv6_hopopts_len; hf_exthdr_item_len_oct = hf_ipv6_hopopts_len_oct; ett_exthdr_proto = ett_ipv6_hopopts_proto; } else if (exthdr_proto == proto_ipv6_dstopts) { hf_exthdr_item_nxt = hf_ipv6_dstopts_nxt; hf_exthdr_item_len = hf_ipv6_dstopts_len; hf_exthdr_item_len_oct = hf_ipv6_dstopts_len_oct; ett_exthdr_proto = ett_ipv6_dstopts_proto; } else { DISSECTOR_ASSERT_NOT_REACHED(); } exthdr_tree = proto_item_add_subtree(ti, ett_exthdr_proto); proto_tree_add_item(exthdr_tree, hf_exthdr_item_nxt, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; ti_len = proto_tree_add_item(exthdr_tree, hf_exthdr_item_len, tvb, offset, 1, ENC_BIG_ENDIAN); ti = proto_tree_add_uint(exthdr_tree, hf_exthdr_item_len_oct, tvb, offset, 1, len); proto_item_set_generated(ti); if (ipv6_exthdr_hide_len_oct_field) { proto_item_set_hidden(ti); proto_item_append_text(ti_len, " (%d bytes)", len); } offset += 1; while (offset < offset_end) { /* there are more options */ opt_type = tvb_get_guint8(tvb, offset); opt_len = tvb_get_guint8(tvb, offset + 1); opt_name = val_to_str_ext(opt_type, &ipv6_opt_type_vals_ext, "Unknown IPv6 Option (%u)"); pi = proto_tree_add_none_format(exthdr_tree, hf_ipv6_opt, tvb, offset, 2 + opt_len, "%s", opt_name); opt_tree = proto_item_add_subtree(pi, ett_ipv6_opt); opt_ti.type = proto_tree_add_item(opt_tree, hf_ipv6_opt_type, tvb, offset, 1, ENC_BIG_ENDIAN); if (opt_type == IP6OPT_PAD1) { /* The Pad1 option is a special case, and contains no data. */ proto_tree_add_item(opt_tree, hf_ipv6_opt_pad1, tvb, offset, 1, ENC_NA); offset += 1; continue; } if ((opt_hdr_type = ipv6_opt_type_hdr(opt_type)) != IPv6_OPT_HDR_ANY) { if (hopopts && (opt_hdr_type == IPv6_OPT_HDR_DST)) { expert_add_info_format(pinfo, opt_ti.type, &ei_ipv6_opt_header_mismatch, "%s must use a destination options header", opt_name); } else if (!hopopts && (opt_hdr_type == IPv6_OPT_HDR_HBH)) { expert_add_info_format(pinfo, opt_ti.type, &ei_ipv6_opt_header_mismatch, "%s must use a hop-by-hop options header", opt_name); } } opt_type_tree = proto_item_add_subtree(opt_ti.type, ett_ipv6_opt_type); proto_tree_add_item(opt_type_tree, hf_ipv6_opt_type_action, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(opt_type_tree, hf_ipv6_opt_type_change, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(opt_type_tree, hf_ipv6_opt_type_rest, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; opt_ti.len = proto_tree_add_item(opt_tree, hf_ipv6_opt_length, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; if (opt_type == IP6OPT_PADN) { /* RFC 2460 states : * "The PadN option is used to insert two or more octets of * padding into the Options area of a header. For N octets of * padding, the Opt Data Len field contains the value N-2, and * the Option Data consists of N-2 zero-valued octets." */ proto_tree_add_item(opt_tree, hf_ipv6_opt_padn, tvb, offset, opt_len, ENC_NA); offset += opt_len; continue; } opt_start = offset; switch (opt_type) { case IP6OPT_JUMBO: offset = dissect_opt_jumbo(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_RPL: offset = dissect_opt_rpl(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_TEL: offset = dissect_opt_tel(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_RTALERT: offset = dissect_opt_rtalert(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_PMTU: offset = dissect_opt_pmtu(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_APN6: offset = dissect_opt_apn6(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_QUICKSTART: offset = dissect_opt_quickstart(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len, iph); break; case IP6OPT_IOAM: offset = dissect_opt_ioam(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_TPF: offset = dissect_opt_tpf(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_CALIPSO: offset = dissect_opt_calipso(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_SMF_DPD: offset = dissect_opt_smf_dpd(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_PDM: offset = dissect_opt_pdm(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_HOME_ADDRESS: offset = dissect_opt_home_address(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_ILNP_NONCE: offset = dissect_opt_ilnp_nonce(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_LIO: offset = dissect_opt_lio(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_MPL: offset = dissect_opt_mpl(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_IP_DFF: offset = dissect_opt_dff(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; case IP6OPT_ENDI: offset = dissect_opt_unknown(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); expert_add_info(pinfo, opt_ti.type, &ei_ipv6_opt_deprecated); break; case IP6OPT_EXP_1E: case IP6OPT_EXP_3E: case IP6OPT_EXP_5E: case IP6OPT_EXP_7E: case IP6OPT_EXP_9E: case IP6OPT_EXP_BE: case IP6OPT_EXP_DE: case IP6OPT_EXP_FE: proto_tree_add_item(opt_tree, hf_ipv6_opt_experimental, tvb, offset, opt_len, ENC_NA); offset += opt_len; break; default: offset = dissect_opt_unknown(tvb, offset, pinfo, opt_tree, &opt_ti, opt_len); break; } if (offset < opt_start + opt_len) { ti = proto_tree_add_item(opt_tree, hf_ipv6_opt_unknown_data, tvb, offset, opt_start + opt_len - offset, ENC_NA); expert_add_info(pinfo, ti, &ei_ipv6_opt_unknown_data); offset = opt_start + opt_len; } } p_add_ipv6_nxt(pinfo, nxt); next_tvb = tvb_new_subset_remaining(tvb, len); ipv6_dissect_next(nxt, next_tvb, pinfo, tree, iph); return tvb_captured_length(tvb); } static int dissect_hopopts(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { col_append_sep_str(pinfo->cinfo, COL_INFO, " , ", "IPv6 hop-by-hop options"); return dissect_opts(tvb, 0, tree, pinfo, (ws_ip6 *)data, proto_ipv6_hopopts); } static int dissect_dstopts(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { col_append_sep_str(pinfo->cinfo, COL_INFO, " , ", "IPv6 destination options"); return dissect_opts(tvb, 0, tree, pinfo, (ws_ip6 *)data, proto_ipv6_dstopts); } /* return value is > G_MAXUINT16, else zero */ /* tvb + offset contains the Hbh header */ static guint32 ipv6_get_jumbo_plen(tvbuff_t *tvb, gint offset) { gint offset_end, hdr_len; gint opt_type, opt_len; guint32 jumbo_plen; if (!tvb_bytes_exist(tvb, offset, 2)) { return 0; } hdr_len = (tvb_get_guint8(tvb, offset + 1) + 1) * 8; offset_end = offset + hdr_len; offset +=2; while (offset < offset_end && tvb_bytes_exist(tvb, offset, 6)) { opt_type = tvb_get_guint8(tvb, offset); offset += 1; if (opt_type == IP6OPT_PAD1) { continue; } opt_len = tvb_get_guint8(tvb, offset); offset += 1; if (opt_type == IP6OPT_JUMBO && opt_len == 4) { jumbo_plen = tvb_get_guint32(tvb, offset, ENC_BIG_ENDIAN); if (jumbo_plen > G_MAXUINT16) { return jumbo_plen; } return 0; } offset += opt_len; } return 0; } struct ipv6_addr_and_mask { uint8_t addr[16]; uint8_t mask[16]; }; typedef struct ipv6_addr_and_mask ipv6_range_t; /* https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml */ static struct ipv6_special_range_s { ipv6_range_t range; const char *name; } ipv6_special_purpose_registry[] = { { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }, "Loopback Address" }, { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }, "Unspecified Address" }, { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, }, "IPv4-mapped Address" }, { { { 0x00, 0x64, 0xff, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, }, "IPv4-IPv6 Translat." }, { { { 0x00, 0x64, 0xff, 0x9b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "IPv4-IPv6 Translat." }, { { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "Discard-Only Address Block" }, { { { 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "IETF Protocol Assignments" }, { { { 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "TEREDO" }, { { { 0x20, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }, "Port Control Protocol Anycast" }, { { { 0x20, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, }, "Traversal Using Relays around NAT Anycast" }, { { { 0x20, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "Benchmarking" }, { { { 0x20, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "AMT" }, { { { 0x20, 0x01, 0x00, 0x04, 0x01, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "AS112-v6" }, { { { 0x20, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "ORCHIDv2" }, { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "Documentation" }, { { { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "6to4" }, { { { 0x26, 0x20, 0x00, 0x4f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "Direct Delegation AS112 Service" }, { { { 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "Unique-Local" }, { { { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, "Link-Local Unicast" }, { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, }, NULL }, }; static bool match_ipv6_range(const ipv6_range_t *range, const ws_in6_addr *addr) { int i; for (i = 0; i < 16; i++) { if (range->addr[i] != (addr->bytes[i] & range->mask[i])) { return false; } } return true; } static void add_ipv6_address_detail(packet_info *pinfo, proto_item *vis, proto_item *invis, tvbuff_t *tvb, int offset, struct ipv6_addr_info_s *addr_info) { proto_item *ti; proto_tree *vtree; /* visible tree */ proto_tree *itree; /* invisible tree */ vtree = proto_item_add_subtree(vis, ett_ipv6_detail); itree = proto_item_add_subtree(invis, ett_ipv6_detail); /* * Internet Protocol Version 6 Address Space * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml */ if (tvb_get_guint8(tvb, offset) == 0xFF) { /* RFC 4291 section 2.4: multicast prefix */ ti = proto_tree_add_string(vtree, *addr_info->hf_addr_space, tvb, offset, 1, "Multicast"); proto_item_set_generated(ti); if (addr_info == &ipv6_src_info) { /* "Shouldn't" see this one as a source */ expert_add_info(pinfo, ti, &ei_ipv6_src_addr_not_multicast); } ti = proto_tree_add_string(itree, hf_ipv6_addr_space, tvb, offset, 1, "Multicast"); proto_item_set_generated(ti); /* * Multicast address scope and flags. * * RFC 4291 Section 2.7: * https://www.rfc-editor.org/rfc/rfc4291#section-2.7 * * RFC 7346: * https://www.rfc-editor.org/rfc/rfc7346.html * * IANA Registry: * https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml#ipv6-scope */ static int *const hf_ipv6_multicast_flags_bits[] = { &hf_ipv6_multicast_flags_reserved, &hf_ipv6_multicast_flags_embed_rp, &hf_ipv6_multicast_flags_network_prefix, &hf_ipv6_multicast_flags_transient, NULL }; /* Add multicast address flags. */ ti = proto_tree_add_bitmask(vtree, tvb, offset, *addr_info->hf_multicast_flags, ett_ipv6_multicast_flags, addr_info->hf_multicast_flags_bits, ENC_BIG_ENDIAN); proto_item_set_generated(ti); ti = proto_tree_add_bitmask(itree, tvb, offset, hf_ipv6_multicast_flags, ett_ipv6_multicast_flags, hf_ipv6_multicast_flags_bits, ENC_BIG_ENDIAN); proto_item_set_generated(ti); /* Add multicast address scope. */ ti = proto_tree_add_item(vtree, *addr_info->hf_multicast_scope, tvb, offset, 2, ENC_BIG_ENDIAN); proto_item_set_generated(ti); ti = proto_tree_add_item(itree, hf_ipv6_multicast_scope, tvb, offset, 2, ENC_BIG_ENDIAN); proto_item_set_generated(ti); } else if ((tvb_get_ntohs(tvb, offset) & 0xFFC0) == 0xFE80) { ti = proto_tree_add_string(vtree, *addr_info->hf_addr_space, tvb, offset, 2, "Link-Local Unicast"); proto_item_set_generated(ti); ti = proto_tree_add_string(itree, hf_ipv6_addr_space, tvb, offset, 2, "Link-Local Unicast"); proto_item_set_generated(ti); } else if ((tvb_get_guint8(tvb, offset) & 0x30) == 0x20) { ti = proto_tree_add_string(vtree, *addr_info->hf_addr_space, tvb, offset, 2, "Global Unicast"); proto_item_set_generated(ti); ti = proto_tree_add_string(itree, hf_ipv6_addr_space, tvb, offset, 2, "Global Unicast"); proto_item_set_generated(ti); } else if ((tvb_get_guint8(tvb, offset) & 0xFE) == 0xFC) { ti = proto_tree_add_string(vtree, *addr_info->hf_addr_space, tvb, offset, 2, "Unique Local Unicast"); proto_item_set_generated(ti); ti = proto_tree_add_string(itree, hf_ipv6_addr_space, tvb, offset, 2, "Unique Local Unicast"); proto_item_set_generated(ti); } else { ti = proto_tree_add_string(vtree, *addr_info->hf_addr_space, tvb, offset, 2, "Reserved by IETF"); proto_item_set_generated(ti); ti = proto_tree_add_string(itree, hf_ipv6_addr_space, tvb, offset, 2, "Reserved by IETF"); proto_item_set_generated(ti); } /* Check for IPv6 address special-purpose ranges. */ const ws_in6_addr *addr = tvb_get_ptr_ipv6(tvb, offset); const struct ipv6_special_range_s *rp; for (rp = ipv6_special_purpose_registry; rp->name != NULL; rp++) { if (match_ipv6_range(&rp->range, addr)) { ti = proto_tree_add_string(vtree, *addr_info->hf_special_purpose, tvb, offset, IPv6_ADDR_SIZE, rp->name); proto_item_set_generated(ti); ti = proto_tree_add_string(itree, hf_ipv6_addr_special_purpose, tvb, offset, IPv6_ADDR_SIZE, rp->name); proto_item_set_generated(ti); break; } } } static void add_ipv6_address(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, struct ipv6_addr_info_s *addr_info) { address addr; const char *name; proto_item *ti, *vis, *invis; vis = proto_tree_add_item(tree, *addr_info->hf_addr, tvb, offset, IPv6_ADDR_SIZE, ENC_NA); invis = proto_tree_add_item(tree, hf_ipv6_addr, tvb, offset, IPv6_ADDR_SIZE, ENC_NA); proto_item_set_hidden(invis); set_address_ipv6_tvb(&addr, tvb, offset); name = address_to_display(pinfo->pool, &addr); if (ipv6_address_detail) { add_ipv6_address_detail(pinfo, vis, invis, tvb, offset, addr_info); } ti = proto_tree_add_string(tree, *addr_info->hf_host, tvb, offset, IPv6_ADDR_SIZE, name); proto_item_set_generated(ti); proto_item_set_hidden(ti); ti = proto_tree_add_string(tree, hf_ipv6_host, tvb, offset, IPv6_ADDR_SIZE, name); proto_item_set_generated(ti); proto_item_set_hidden(ti); } #define ADDRESS_SET_GENERATED_HIDDEN(ti) \ G_STMT_START { \ proto_item_set_generated(ti); \ if (i > 0) proto_item_set_hidden(ti); \ } G_STMT_END /* RFC 3056 section 2 */ static void add_ipv6_address_6to4(proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_gateway, gint hf_sla_id) { if (tvb_get_ntohs(tvb, offset) != 0x2002) return; struct { gint gateway, sla_id; } hf[2] = { { hf_gateway, hf_sla_id}, { hf_ipv6_6to4_gateway_ipv4, hf_ipv6_6to4_sla_id} }; proto_item *ti; for (int i = 0; i < 2; i++) { ti = proto_tree_add_item(tree, hf[i].gateway, tvb, offset + 2, 4, ENC_BIG_ENDIAN); ADDRESS_SET_GENERATED_HIDDEN(ti); ti = proto_tree_add_item(tree, hf[i].sla_id, tvb, offset + 6, 2, ENC_BIG_ENDIAN); ADDRESS_SET_GENERATED_HIDDEN(ti); } } /* RFC 4380 section 4 */ static void add_ipv6_address_teredo(proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_server, gint hf_port, gint hf_client) { if (tvb_get_ntohl(tvb, offset) != 0x20010000) return; guint16 mapped_port = tvb_get_ntohs(tvb, offset + 10) ^ 0xffff; guint32 client_v4 = tvb_get_ipv4(tvb, offset + 12) ^ 0xffffffff; struct { gint server, port, client; } hf[2] = { { hf_server, hf_port, hf_client }, { hf_ipv6_teredo_server_ipv4, hf_ipv6_teredo_port, hf_ipv6_teredo_client_ipv4 } }; proto_item *ti; for (int i = 0; i < 2; i++) { ti = proto_tree_add_item(tree, hf[i].server, tvb, offset + 4, 4, ENC_BIG_ENDIAN); ADDRESS_SET_GENERATED_HIDDEN(ti); ti = proto_tree_add_uint(tree, hf[i].port, tvb, offset + 10, 2, mapped_port); ADDRESS_SET_GENERATED_HIDDEN(ti); ti = proto_tree_add_ipv4(tree, hf[i].client, tvb, offset + 12, 4, client_v4); ADDRESS_SET_GENERATED_HIDDEN(ti); } } /* RFC 4291 appendix A */ static void add_ipv6_address_slaac(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_slaac) { if (!(tvb_get_guint8(tvb, offset + 8) & 0x02) || !(tvb_get_ntohs(tvb, offset + 11) == 0xfffe)) { return; } guint8 *mac_addr = (guint8 *)wmem_alloc(pinfo->pool, 6); tvb_memcpy(tvb, mac_addr, offset + 8, 3); tvb_memcpy(tvb, mac_addr+3, offset + 13, 3); mac_addr[0] &= ~0x02; struct { gint mac; } hf[2] = { { hf_slaac }, { hf_ipv6_slaac_mac } }; proto_item *ti; for (int i = 0; i < 2; i++) { ti = proto_tree_add_ether(tree, hf[i].mac, tvb, offset + 8, 8, mac_addr); ADDRESS_SET_GENERATED_HIDDEN(ti); } } /* RFC 5214 section 6.1 */ static void add_ipv6_address_isatap(proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_isatap) { if ((tvb_get_ntohl(tvb, offset + 8) & 0xfcffffff) != 0x00005efe) return; struct { gint ipv4; } hf[2] = { { hf_isatap }, { hf_ipv6_isatap_ipv4 } }; proto_item *ti; for (int i = 0; i < 2; i++) { ti = proto_tree_add_item(tree, hf[i].ipv4, tvb, offset + 12, 4, ENC_BIG_ENDIAN); ADDRESS_SET_GENERATED_HIDDEN(ti); } } /* RFC 6052 */ static void add_ipv6_address_embed_ipv4(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, gint hf_embed) { /* Section 2.1: Well-Known Prefix for IPv4-Embedded IPv6 Address: 64:FF9B::/96 */ static const guint8 well_known_prefix[] = { 0x00, 0x64, 0xFF, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ws_in6_addr ipv6_addr; ws_in4_addr ipv4_addr; gint ipv4_prefix; gint ipv4_offset; gboolean ipv6_embed_ipv4 = false; if (tvb_memeql(tvb, offset, well_known_prefix, sizeof well_known_prefix) == 0) { ipv4_addr = tvb_get_bits32(tvb, (offset * 8) + 96, 32, ENC_BIG_ENDIAN); ipv4_prefix = 96; ipv4_offset = 96; ipv6_embed_ipv4 = true; } else { for (size_t j = 0; j < number_of_nat64_prefix; j++) { if (nat64_prefix_uats[j].prefix_len <= nat64_prefix_uats[j].prefix_wildcard_len) { continue; } if (ws_inet_pton6(nat64_prefix_uats[j].ipaddr, &ipv6_addr)) { if (tvb_memeql(tvb, offset, (const guint8 *)&ipv6_addr, (nat64_prefix_uats[j].prefix_len - nat64_prefix_uats[j].prefix_wildcard_len) / 8) == 0) { switch (nat64_prefix_uats[j].prefix_len) { case 32: ipv4_addr = tvb_get_bits32(tvb, (offset * 8) + 32, 32, ENC_BIG_ENDIAN); break; case 40: ipv4_addr = tvb_get_bits32(tvb, (offset * 8) + 40, 24, ENC_BIG_ENDIAN) << 8; ipv4_addr |= tvb_get_bits32(tvb, (offset * 8) + 72, 8, ENC_BIG_ENDIAN); break; case 48: ipv4_addr = tvb_get_bits32(tvb, (offset * 8) + 48, 16, ENC_BIG_ENDIAN) << 16; ipv4_addr |= tvb_get_bits32(tvb, (offset * 8) + 72, 16, ENC_BIG_ENDIAN); break; case 56: ipv4_addr = tvb_get_bits32(tvb, (offset * 8) + 56, 8, ENC_BIG_ENDIAN) << 24; ipv4_addr |= tvb_get_bits32(tvb, (offset * 8) + 72, 24, ENC_BIG_ENDIAN); break; case 64: ipv4_addr = tvb_get_bits32(tvb, (offset * 8) + 72, 32, ENC_BIG_ENDIAN); break; case 96: ipv4_addr = tvb_get_bits32(tvb, (offset * 8) + 96, 32, ENC_BIG_ENDIAN); break; default: DISSECTOR_ASSERT_NOT_REACHED(); } ipv4_prefix = nat64_prefix_uats[j].prefix_len; if (ipv4_prefix != 64) { ipv4_offset = ipv4_prefix; } else { ipv4_offset = 72; } ipv6_embed_ipv4 = true; break; } } } } if (ipv6_embed_ipv4) { proto_item *ti; // The prefix ti = proto_tree_add_item(tree, hf_ipv6_embed_ipv4_prefix, tvb, offset, ipv4_prefix / 8, ENC_NA); proto_item_set_generated(ti); // Majority of IPv4 address is after u-field if (ipv4_prefix >= 56) { if (ipv4_prefix < 96) { ti = proto_tree_add_item(tree, hf_ipv6_embed_ipv4_u, tvb, offset + 8, 1, ENC_NA); proto_item_set_generated(ti); } if (tvb_get_guint8(tvb, offset + 8)) { expert_add_info(pinfo, ti, &ei_ipv6_embed_ipv4_u_value); } } // IPv4 embedded address ipv4_addr = g_ntohl(ipv4_addr); ti = proto_tree_add_ipv4(tree, hf_embed, tvb, offset + (ipv4_offset / 8), (ipv4_offset > 32 && ipv4_offset < 64) ? 5 : 4, ipv4_addr); proto_item_set_generated(ti); ti = proto_tree_add_ipv4(tree, hf_ipv6_embed_ipv4, tvb, offset + (ipv4_offset / 8), (ipv4_offset > 32 && ipv4_offset < 64) ? 5 : 4, ipv4_addr); proto_item_set_generated(ti); // Majority of IPv4 address is before u-field if (ipv4_prefix < 56) { ti = proto_tree_add_item(tree, hf_ipv6_embed_ipv4_u, tvb, offset + 8, 1, ENC_NA); proto_item_set_generated(ti); if (tvb_get_guint8(tvb, offset + 8)) { expert_add_info(pinfo, ti, &ei_ipv6_embed_ipv4_u_value); } } // Suffix, if present if (ipv4_prefix < 96) { ti = proto_tree_add_item(tree, hf_ipv6_embed_ipv4_suffix, tvb, offset + ((72 + ipv4_prefix - 32) / 8), (56 - (ipv4_prefix - 32)) / 8, ENC_NA); proto_item_set_generated(ti); } } } 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_ipv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { proto_tree *ipv6_tree, *pt; proto_item *ipv6_item, *ti, *pi; proto_item *ti_ipv6_plen = NULL, *ti_ipv6_version; guint8 ip6_tcls, ip6_nxt, ip6_hlim; guint32 ip6_flow; const ws_in6_addr *ip6_src, *ip6_dst; guint32 ip6_plen = 0, jumbo_plen = 0; guint32 plen; int offset; guint reported_plen; tvbuff_t *next_tvb; gboolean save_fragmented; int version; ws_ip6 *iph; offset = 0; col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPv6"); col_clear(pinfo->cinfo, COL_INFO); ipv6_item = proto_tree_add_item(tree, proto_ipv6, tvb, offset, IPv6_HDR_SIZE, ENC_NA); ipv6_tree = proto_item_add_subtree(ipv6_item, ett_ipv6_proto); /* Validate IP version (6) */ version = tvb_get_bits8(tvb, (offset + IP6H_CTL_VFC) * 8, 4); ti_ipv6_version = proto_tree_add_bits_item(ipv6_tree, hf_ipv6_version, tvb, (offset + IP6H_CTL_VFC) * 8, 4, ENC_BIG_ENDIAN); pi = proto_tree_add_item(ipv6_tree, hf_ip_version, tvb, offset + IP6H_CTL_VFC, 1, ENC_BIG_ENDIAN); proto_item_append_text(pi, " [This field makes the filter match on \"ip.version == 6\" possible]"); proto_item_set_hidden(pi); if (version != 6) { col_add_fstr(pinfo->cinfo, COL_INFO, "Bogus IPv6 version (%u, must be 6)", version); expert_add_info_format(pinfo, ti_ipv6_version, &ei_ipv6_bogus_ipv6_version, "Bogus IPv6 version"); return offset + IP6H_CTL_VFC; } /* Validate header size (40 bytes) */ if (tvb_reported_length(tvb) < IPv6_HDR_SIZE) { col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid IPv6 header (%u bytes, need exactly 40)", tvb_reported_length(tvb)); expert_add_info_format(pinfo, ipv6_item, &ei_ipv6_invalid_header, "IPv6 header must be exactly 40 bytes"); } /* !!! warning: (4-bit) version, (6-bit) DSCP, (2-bit) ECN and (20-bit) Flow */ ti = proto_tree_add_item(ipv6_tree, hf_ipv6_tclass, tvb, offset + IP6H_CTL_VFC, 4, ENC_BIG_ENDIAN); ip6_tcls = tvb_get_bits8(tvb, (offset + IP6H_CTL_VFC) * 8 + 4, 8); proto_item_append_text(ti, " (DSCP: %s, ECN: %s)", val_to_str_ext_const(IPDSFIELD_DSCP(ip6_tcls), &dscp_short_vals_ext, "Unknown"), val_to_str_ext_const(IPDSFIELD_ECN(ip6_tcls), &ecn_short_vals_ext, "Unknown")); pt = proto_item_add_subtree(ti, ett_ipv6_traffic_class); proto_tree_add_item(pt, hf_ipv6_tclass_dscp, tvb, offset + IP6H_CTL_VFC, 4, ENC_BIG_ENDIAN); proto_tree_add_item(pt, hf_ipv6_tclass_ecn, tvb, offset + IP6H_CTL_VFC, 4, ENC_BIG_ENDIAN); /* Set DSCP column */ col_add_str(pinfo->cinfo, COL_DSCP_VALUE, val_to_str_ext(IPDSFIELD_DSCP(ip6_tcls), &dscp_short_vals_ext, "%u")); proto_tree_add_item_ret_uint(ipv6_tree, hf_ipv6_flow, tvb, offset + IP6H_CTL_FLOW + 1, 3, ENC_BIG_ENDIAN, &ip6_flow); ip6_plen = tvb_get_guint16(tvb, offset + IP6H_CTL_PLEN, ENC_BIG_ENDIAN); ip6_nxt = tvb_get_guint8(tvb, offset + IP6H_CTL_NXT); if (ipv6_tso_supported && ip6_plen == 0 && ip6_nxt != IP_PROTO_HOPOPTS && ip6_nxt != IP_PROTO_NONE) { ip6_plen = tvb_reported_length(tvb) - IPv6_HDR_SIZE; pi = proto_tree_add_uint_format_value(ipv6_tree, hf_ipv6_plen, tvb, offset + IP6H_CTL_PLEN, 2, ip6_plen, "%u bytes (reported as 0, presumed to be because " "of \"TCP segmentation offload\" (TSO))", ip6_plen); proto_item_set_generated(pi); } else { ti_ipv6_plen = proto_tree_add_item(ipv6_tree, hf_ipv6_plen, tvb, offset + IP6H_CTL_PLEN, 2, ENC_BIG_ENDIAN); if (ip6_plen == 0 && ip6_nxt != IP_PROTO_HOPOPTS && ip6_nxt != IP_PROTO_NONE) { expert_add_info(pinfo, ti_ipv6_plen, &ei_ipv6_plen_zero); } } proto_tree_add_item(ipv6_tree, hf_ipv6_nxt, tvb, offset + IP6H_CTL_NXT, 1, ENC_NA); proto_tree_add_item(ipv6_tree, hf_ipv6_hlim, tvb, offset + IP6H_CTL_HLIM, 1, ENC_BIG_ENDIAN); ip6_hlim = tvb_get_guint8(tvb, offset + IP6H_CTL_HLIM); /* Source address */ add_ipv6_address(pinfo, ipv6_tree, tvb, offset + IP6H_SRC, &ipv6_src_info); ip6_src = tvb_get_ptr_ipv6(tvb, offset + IP6H_SRC); alloc_address_wmem_ipv6(pinfo->pool, &pinfo->net_src, ip6_src); copy_address_shallow(&pinfo->src, &pinfo->net_src); /* Destination address */ add_ipv6_address(pinfo, ipv6_tree, tvb, offset + IP6H_DST, &ipv6_dst_info); ip6_dst = tvb_get_ptr_ipv6(tvb, offset + IP6H_DST); alloc_address_wmem_ipv6(pinfo->pool, &pinfo->net_dst, ip6_dst); copy_address_shallow(&pinfo->dst, &pinfo->net_dst); if (tree) { if (ipv6_summary_in_tree) { proto_item_append_text(ipv6_item, ", Src: %s, Dst: %s", address_with_resolution_to_str(pinfo->pool, &pinfo->src), address_with_resolution_to_str(pinfo->pool, &pinfo->dst)); } /* Add the different items for the address */ add_ipv6_address_6to4(ipv6_tree, tvb, offset + IP6H_SRC, hf_ipv6_src_6to4_gateway_ipv4, hf_ipv6_src_6to4_sla_id); add_ipv6_address_6to4(ipv6_tree, tvb, offset + IP6H_DST, hf_ipv6_dst_6to4_gateway_ipv4, hf_ipv6_dst_6to4_sla_id); add_ipv6_address_teredo(ipv6_tree, tvb, offset + IP6H_SRC, hf_ipv6_src_teredo_server_ipv4, hf_ipv6_src_teredo_port, hf_ipv6_src_teredo_client_ipv4); add_ipv6_address_teredo(ipv6_tree, tvb, offset + IP6H_DST, hf_ipv6_dst_teredo_server_ipv4, hf_ipv6_dst_teredo_port, hf_ipv6_dst_teredo_client_ipv4); add_ipv6_address_slaac(pinfo, ipv6_tree, tvb, offset + IP6H_SRC, hf_ipv6_src_slaac_mac); add_ipv6_address_slaac(pinfo, ipv6_tree, tvb, offset + IP6H_DST, hf_ipv6_dst_slaac_mac); add_ipv6_address_isatap(ipv6_tree, tvb, offset + IP6H_SRC, hf_ipv6_src_isatap_ipv4); add_ipv6_address_isatap(ipv6_tree, tvb, offset + IP6H_DST, hf_ipv6_dst_isatap_ipv4); add_ipv6_address_embed_ipv4(pinfo, ipv6_tree, tvb, offset + IP6H_SRC, hf_ipv6_src_embed_ipv4); add_ipv6_address_embed_ipv4(pinfo, ipv6_tree, tvb, offset + IP6H_DST, hf_ipv6_dst_embed_ipv4); if (ipv6_use_geoip) { add_geoip_info(ipv6_tree, pinfo, tvb, offset, ip6_src, ip6_dst); } } /* Increment offset to point to next header (may be an extension header) */ offset += IPv6_HDR_SIZE; /* Check for Jumbo option */ plen = ip6_plen; if (plen == 0 && ip6_nxt == IP_PROTO_HOPOPTS) { jumbo_plen = ipv6_get_jumbo_plen(tvb, offset); if (jumbo_plen != 0) { proto_item_append_text(ti_ipv6_plen, " (Jumbogram)"); plen = jumbo_plen; } else { /* IPv6 length zero is invalid if there is a hop-by-hop header without jumbo option */ col_add_fstr(pinfo->cinfo, COL_INFO, "Invalid IPv6 payload length"); expert_add_info(pinfo, ti_ipv6_plen, &ei_ipv6_opt_jumbo_missing); } } reported_plen = tvb_reported_length(tvb) - IPv6_HDR_SIZE; if (!pinfo->flags.in_error_pkt && plen > reported_plen) { expert_add_info_format(pinfo, ti_ipv6_plen, &ei_ipv6_plen_exceeds_framing, "IPv6 payload length exceeds framing length (%d bytes)", reported_plen); } /* Fill in IP header fields for subdissectors */ iph = wmem_new0(pinfo->pool, ws_ip6); iph->ip6_ver = 6; iph->ip6_tc = ip6_tcls; iph->ip6_flw = ip6_flow; iph->ip6_len = plen; iph->ip6_nxt = ip6_nxt; iph->ip6_hop = ip6_hlim; alloc_address_wmem_ipv6(pinfo->pool, &iph->ip6_src, ip6_src); alloc_address_wmem_ipv6(pinfo->pool, &iph->ip6_dst, ip6_dst); /* Shared state between IPv6 header and extensions. */ ipv6_pinfo_t *ipv6_pinfo = wmem_new0(pinfo->pool, ipv6_pinfo_t); ipv6_pinfo->ip6_plen = ip6_plen; ipv6_pinfo->jumbo_plen = jumbo_plen; ipv6_pinfo->frag_plen = ip6_plen; /* updated by extension header dissectors, if any */ if (!ipv6_exthdr_under_root) { ipv6_pinfo->ipv6_tree = ipv6_tree; ipv6_pinfo->ipv6_item_len = IPv6_HDR_SIZE; } p_add_proto_data(pinfo->pool, pinfo, proto_ipv6, IPV6_PROTO_PINFO, ipv6_pinfo); /* Adjust the length of this tvbuff to include only the IPv6 datagram. */ set_actual_length(tvb, IPv6_HDR_SIZE + plen); /* Only export after adjusting the length */ export_pdu(tvb, pinfo); save_fragmented = pinfo->fragmented; p_add_ipv6_nxt(pinfo, ip6_nxt); next_tvb = tvb_new_subset_remaining(tvb, offset); ipv6_dissect_next(ip6_nxt, next_tvb, pinfo, tree, iph); pinfo->fragmented = save_fragmented; return tvb_captured_length(tvb); } void ipv6_dissect_next(guint nxt, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, ws_ip6 *iph) { dissector_handle_t nxt_handle; ipv6_pinfo_t *ipv6_pinfo = p_get_ipv6_pinfo(pinfo); /* https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml#extension-header */ switch (nxt) { case IP_PROTO_HOPOPTS: case IP_PROTO_ROUTING: case IP_PROTO_FRAGMENT: //case IP_PROTO_ESP: Even though ESP is technically an extension header, // we treat it as a payload container. case IP_PROTO_AH: case IP_PROTO_DSTOPTS: case IP_PROTO_MIPV6: //case IP_PROTO_HIP: Even though HIP is technically an extension header, the only defined // next header is IP_NONE. Also the HIP dissector is not ready for this. case IP_PROTO_SHIM6: nxt_handle = dissector_get_uint_handle(ip_dissector_table, nxt); break; default: nxt_handle = NULL; break; } if (nxt_handle != NULL) { call_dissector_with_data(nxt_handle, tvb, pinfo, tree, iph); return; } /* * Done with extension header chain */ if (ipv6_pinfo != NULL && ipv6_pinfo->ipv6_tree != NULL) { /* Set IPv6 Header length */ proto_item_set_len(proto_tree_get_parent(ipv6_pinfo->ipv6_tree), ipv6_pinfo->ipv6_item_len); ipv6_pinfo->ipv6_tree = NULL; } if (iph != NULL && iph->ip6_ver == 6) { iph->ip6_nxt = nxt; /* upper-layer protocol more useful */ tap_queue_packet(ipv6_tap, pinfo, iph); } if (nxt == IP_PROTO_NONE) { col_set_str(pinfo->cinfo, COL_INFO, "IPv6 no next header"); call_data_dissector(tvb, pinfo, tree); return; } if (ip_try_dissect(try_heuristic_first, nxt, tvb, pinfo, tree, iph)) { return; } /* Unknown protocol. */ col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown IP Protocol: %s (%u)", ipprotostr(nxt), nxt); call_data_dissector(tvb, pinfo, tree); } void proto_register_ipv6(void) { static hf_register_info hf_ipv6[] = { { &hf_ipv6_version, { "Version", "ipv6.version", FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL } }, { &hf_ip_version, { "Version", "ip.version", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL } }, { &hf_ipv6_tclass, { "Traffic Class", "ipv6.tclass", FT_UINT32, BASE_HEX, NULL, 0x0FF00000, NULL, HFILL } }, { &hf_ipv6_tclass_dscp, { "Differentiated Services Codepoint", "ipv6.tclass.dscp", FT_UINT32, BASE_DEC | BASE_EXT_STRING, &dscp_vals_ext, 0x0FC00000, NULL, HFILL } }, { &hf_ipv6_tclass_ecn, { "Explicit Congestion Notification", "ipv6.tclass.ecn", FT_UINT32, BASE_DEC | BASE_EXT_STRING, &ecn_vals_ext, 0x00300000, NULL, HFILL } }, { &hf_ipv6_flow, { "Flow Label", "ipv6.flow", FT_UINT24, BASE_HEX, NULL, 0x0FFFFF, NULL, HFILL } }, { &hf_ipv6_plen, { "Payload Length", "ipv6.plen", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_nxt, { "Next Header", "ipv6.nxt", FT_UINT8, BASE_DEC | BASE_EXT_STRING, &ipproto_val_ext, 0x0, NULL, HFILL } }, { &hf_ipv6_hlim, { "Hop Limit", "ipv6.hlim", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_src, { "Source Address", "ipv6.src", FT_IPv6, BASE_NONE, NULL, 0x0, "Source IPv6 Address", HFILL } }, { &hf_ipv6_src_addr_space, { "Source Address Space", "ipv6.src_addr_space", FT_STRING, BASE_NONE, NULL, 0x0, "Source IPv6 Address Space", HFILL } }, { &hf_ipv6_src_multicast_flags, { "Source Address Multicast Flags", "ipv6.src_multicast_flags", FT_UINT16, BASE_HEX, NULL, 0x00F0, NULL, HFILL } }, { &hf_ipv6_src_multicast_flags_transient, { "Source Address Transient Multicast Flag", "ipv6.src_multicast_flags.transient", FT_BOOLEAN, 16, NULL, 0x0010, NULL, HFILL } }, { &hf_ipv6_src_multicast_flags_network_prefix, { "Source Address Network Prefix Multicast Flag", "ipv6.src_multicast_flags.network_prefix", FT_BOOLEAN, 16, NULL, 0x0020, NULL, HFILL } }, { &hf_ipv6_src_multicast_flags_embed_rp, { "Source Address RP Multicast Flag", "ipv6.src_multicast_flags.embed_rp", FT_BOOLEAN, 16, NULL, 0x0040, NULL, HFILL } }, { &hf_ipv6_src_multicast_flags_reserved, { "Source Address Reserved Multicast Flag", "ipv6.src_multicast_flags.reserved", FT_UINT16, BASE_DEC, NULL, 0x0080, NULL, HFILL } }, { &hf_ipv6_src_multicast_scope, { "Source Address Multicast Scope", "ipv6.src_multicast_scope", FT_UINT16, BASE_HEX, VALS(ipv6_multicast_scope_vals), 0x000F, NULL, HFILL } }, { &hf_ipv6_src_special_purpose, { "Source Address Special-Purpose Allocation", "ipv6.src_special_purpose", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_src_host, { "Source Host", "ipv6.src_host", FT_STRING, BASE_NONE, NULL, 0x0, "Source IPv6 Host", HFILL } }, { &hf_ipv6_src_slaac_mac, { "Source SLAAC MAC", "ipv6.src_slaac_mac", FT_ETHER, BASE_NONE, NULL, 0x0, "Source IPv6 Stateless Address Autoconfiguration (SLAAC) 48-bit MAC Identifier", HFILL } }, { &hf_ipv6_src_isatap_ipv4, { "Source ISATAP IPv4", "ipv6.src_isatap_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Source IPv6 ISATAP Encapsulated IPv4 Address", HFILL } }, { &hf_ipv6_src_6to4_gateway_ipv4, { "Source 6to4 Gateway IPv4", "ipv6.src_6to4_gw_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Source IPv6 6to4 Gateway IPv4 Address", HFILL } }, { &hf_ipv6_src_6to4_sla_id, { "Source 6to4 SLA ID", "ipv6.src_6to4_sla_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Source IPv6 6to4 SLA ID", HFILL } }, { &hf_ipv6_src_teredo_server_ipv4, { "Source Teredo Server IPv4", "ipv6.src_ts_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Source IPv6 Teredo Server Encapsulated IPv4 Address", HFILL } }, { &hf_ipv6_src_teredo_port, { "Source Teredo Port", "ipv6.src_tc_port", FT_UINT16, BASE_DEC, NULL, 0x0, "Source IPv6 Teredo Client Mapped Port", HFILL } }, { &hf_ipv6_src_teredo_client_ipv4, { "Source Teredo Client IPv4", "ipv6.src_tc_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Source IPv6 Teredo Client Encapsulated IPv4 Address", HFILL } }, { &hf_ipv6_src_embed_ipv4, { "Source Embedded IPv4", "ipv6.src_embed_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Source IPv4-Embedded IPv6 Address", HFILL } }, { &hf_ipv6_dst, { "Destination Address", "ipv6.dst", FT_IPv6, BASE_NONE, NULL, 0x0, "Destination IPv6 Address", HFILL } }, { &hf_ipv6_dst_addr_space, { "Destination Address Space", "ipv6.dst_addr_space", FT_STRING, BASE_NONE, NULL, 0x0, "Destination IPv6 Address Space", HFILL } }, { &hf_ipv6_dst_multicast_flags, { "Destination Address Multicast Flags", "ipv6.dst_multicast_flags", FT_UINT16, BASE_HEX, NULL, 0x00F0, NULL, HFILL } }, { &hf_ipv6_dst_multicast_flags_transient, { "Destination Address Transient Multicast Flag", "ipv6.dst_multicast_flags.transient", FT_BOOLEAN, 16, NULL, 0x0010, NULL, HFILL } }, { &hf_ipv6_dst_multicast_flags_network_prefix, { "Destination Address Network Prefix Multicast Flag", "ipv6.dst_multicast_flags.network_prefix", FT_BOOLEAN, 16, NULL, 0x0020, NULL, HFILL } }, { &hf_ipv6_dst_multicast_flags_embed_rp, { "Destination Address RP Multicast Flag", "ipv6.dst_multicast_flags.embed_rp", FT_BOOLEAN, 16, NULL, 0x0040, NULL, HFILL } }, { &hf_ipv6_dst_multicast_flags_reserved, { "Destination Address Reserved Multicast Flag", "ipv6.dst_multicast_flags.reserved", FT_UINT16, BASE_DEC, NULL, 0x0080, NULL, HFILL } }, { &hf_ipv6_dst_multicast_scope, { "Destination Address Multicast Scope", "ipv6.dst_multicast_scope", FT_UINT16, BASE_HEX, VALS(ipv6_multicast_scope_vals), 0x000F, NULL, HFILL } }, { &hf_ipv6_dst_special_purpose, { "Destination Address Special-Purpose Allocation", "ipv6.dst_special_purpose", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_dst_host, { "Destination Host", "ipv6.dst_host", FT_STRING, BASE_NONE, NULL, 0x0, "Destination IPv6 Host", HFILL } }, { &hf_ipv6_dst_slaac_mac, { "Destination SLAAC MAC", "ipv6.dst_slaac_mac", FT_ETHER, BASE_NONE, NULL, 0x0, "Destination IPv6 Stateless Address Autoconfiguration (SLAAC) 48-bit MAC Identifier", HFILL } }, { &hf_ipv6_dst_isatap_ipv4, { "Destination ISATAP IPv4", "ipv6.dst_isatap_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Destination IPv6 ISATAP Encapsulated IPv4 Address", HFILL } }, { &hf_ipv6_dst_6to4_gateway_ipv4, { "Destination 6to4 Gateway IPv4", "ipv6.dst_6to4_gw_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Destination IPv6 6to4 Gateway IPv4 Address", HFILL } }, { &hf_ipv6_dst_6to4_sla_id, { "Destination 6to4 SLA ID", "ipv6.dst_6to4_sla_id", FT_UINT16, BASE_DEC, NULL, 0x0, "Destination IPv6 6to4 SLA ID", HFILL } }, { &hf_ipv6_dst_teredo_server_ipv4, { "Destination Teredo Server IPv4", "ipv6.dst_ts_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Destination IPv6 Teredo Server Encapsulated IPv4 Address", HFILL } }, { &hf_ipv6_dst_teredo_port, { "Destination Teredo Port", "ipv6.dst_tc_port", FT_UINT16, BASE_DEC, NULL, 0x0, "Destination IPv6 Teredo Client Mapped Port", HFILL } }, { &hf_ipv6_dst_teredo_client_ipv4, { "Destination Teredo Client IPv4", "ipv6.dst_tc_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Destination IPv6 Teredo Client Encapsulated IPv4 Address", HFILL } }, { &hf_ipv6_dst_embed_ipv4, { "Destination Embedded IPv4", "ipv6.dst_embed_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "Destination IPv4-Embedded IPv6 Address", HFILL } }, { &hf_ipv6_addr, { "Source or Destination Address", "ipv6.addr", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_addr_space, { "Source or Destination Address Space", "ipv6.addr_space", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_multicast_flags, { "Source or Destination Address Multicast Flags", "ipv6.multicast_flags", FT_UINT16, BASE_HEX, NULL, 0x00F0, NULL, HFILL } }, { &hf_ipv6_multicast_flags_transient, { "Source or Destination Address Transient Multicast Flag", "ipv6.multicast_flags.transient", FT_BOOLEAN, 16, NULL, 0x0010, NULL, HFILL } }, { &hf_ipv6_multicast_flags_network_prefix, { "Source or Destination Address Network Prefix Multicast Flag", "ipv6.multicast_flags.network_prefix", FT_BOOLEAN, 16, NULL, 0x0020, NULL, HFILL } }, { &hf_ipv6_multicast_flags_embed_rp, { "Source or Destination Address RP Multicast Flag", "ipv6.multicast_flags.embed_rp", FT_BOOLEAN, 16, NULL, 0x0040, NULL, HFILL } }, { &hf_ipv6_multicast_flags_reserved, { "Source or Destination Address Reserved Multicast Flag", "ipv6.multicast_flags.reserved", FT_UINT16, BASE_DEC, NULL, 0x0080, NULL, HFILL } }, { &hf_ipv6_multicast_scope, { "Source or Destination Address Multicast Scope", "ipv6.multicast_scope", FT_UINT16, BASE_HEX, VALS(ipv6_multicast_scope_vals), 0x000F, NULL, HFILL } }, { &hf_ipv6_addr_special_purpose, { "Source or Destination Address Special-Purpose Allocation", "ipv6.addr_special_purpose", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_host, { "Source or Destination Host", "ipv6.host", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_slaac_mac, { "SLAAC MAC", "ipv6.slaac_mac", FT_ETHER, BASE_NONE, NULL, 0x0, "IPv6 Stateless Address Autoconfiguration (SLAAC) 48-bit MAC Identifier", HFILL } }, { &hf_ipv6_isatap_ipv4, { "ISATAP IPv4", "ipv6.isatap_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "IPv6 ISATAP Encapsulated IPv4 Address", HFILL } }, { &hf_ipv6_6to4_gateway_ipv4, { "6to4 Gateway IPv4", "ipv6.6to4_gw_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "IPv6 6to4 Gateway IPv4 Address", HFILL } }, { &hf_ipv6_6to4_sla_id, { "6to4 SLA ID", "ipv6.6to4_sla_id", FT_UINT16, BASE_DEC, NULL, 0x0, "IPv6 6to4 SLA ID", HFILL } }, { &hf_ipv6_teredo_server_ipv4, { "Teredo Server IPv4", "ipv6.ts_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "IPv6 Teredo Server Encapsulated IPv4 Address", HFILL } }, { &hf_ipv6_teredo_port, { "Teredo Port", "ipv6.tc_port", FT_UINT16, BASE_DEC, NULL, 0x0, "IPv6 Teredo Client Mapped Port", HFILL } }, { &hf_ipv6_teredo_client_ipv4, { "Teredo Client IPv4", "ipv6.tc_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "IPv6 Teredo Client Encapsulated IPv4 Address", HFILL } }, { &hf_ipv6_embed_ipv4_prefix, { "Embedded IPv4 Prefix", "ipv6.embed_ipv4_prefix", FT_BYTES, BASE_NONE, NULL, 0x0, "IPv4-Embedded IPv6 Address Prefix", HFILL } }, { &hf_ipv6_embed_ipv4, { "Embedded IPv4", "ipv6.embed_ipv4", FT_IPv4, BASE_NONE, NULL, 0x0, "IPv4-Embedded IPv6 Address", HFILL } }, { &hf_ipv6_embed_ipv4_u, { "Embedded IPv4 u field", "ipv6.embed_ipv4_u", FT_BYTES, BASE_NONE, NULL, 0x0, "IPv4-Embedded IPv6 Address u field", HFILL } }, { &hf_ipv6_embed_ipv4_suffix, { "Embedded IPv4 Suffix", "ipv6.embed_ipv4_suffix", FT_BYTES, BASE_NONE, NULL, 0x0, "IPv4-Embedded IPv6 Address Suffix", HFILL } }, { &hf_geoip_country, { "Source or Destination GeoIP Country", "ipv6.geoip.country", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_country_iso, { "Source or Destination GeoIP ISO Two Letter Country Code", "ipv6.geoip.country_iso", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_city, { "Source or Destination GeoIP City", "ipv6.geoip.city", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_as_number, { "Source or Destination GeoIP AS Number", "ipv6.geoip.asnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_as_org, { "Source or Destination GeoIP AS Organization", "ipv6.geoip.org", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_latitude, { "Source or Destination GeoIP Latitude", "ipv6.geoip.lat", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_longitude, { "Source or Destination GeoIP Longitude", "ipv6.geoip.lon", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_src_summary, { "Source GeoIP", "ipv6.geoip.src_summary", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_src_country, { "Source GeoIP Country", "ipv6.geoip.src_country", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_src_country_iso, { "Source GeoIP ISO Two Letter Country Code", "ipv6.geoip.src_country_iso", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_src_city, { "Source GeoIP City", "ipv6.geoip.src_city", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_src_as_number, { "Source GeoIP AS Number", "ipv6.geoip.src_asnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_src_as_org, { "Source GeoIP AS Organization", "ipv6.geoip.src_org", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_src_latitude, { "Source GeoIP Latitude", "ipv6.geoip.src_lat", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_src_longitude, { "Source GeoIP Longitude", "ipv6.geoip.src_lon", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_dst_summary, { "Destination GeoIP", "ipv6.geoip.dst_summary", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_dst_country, { "Destination GeoIP Country", "ipv6.geoip.dst_country", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_dst_country_iso, { "Destination GeoIP ISO Two Letter Country Code", "ipv6.geoip.dst_country_iso", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_dst_city, { "Destination GeoIP City", "ipv6.geoip.dst_city", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_dst_as_number, { "Destination GeoIP AS Number", "ipv6.geoip.dst_asnum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_dst_as_org, { "Destination GeoIP AS Organization", "ipv6.geoip.dst_org", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_dst_latitude, { "Destination GeoIP Latitude", "ipv6.geoip.dst_lat", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_geoip_dst_longitude, { "Destination GeoIP Longitude", "ipv6.geoip.dst_lon", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt, { "IPv6 Option", "ipv6.opt", FT_NONE, BASE_NONE, NULL, 0x0, "Option", HFILL } }, { &hf_ipv6_opt_type, { "Type", "ipv6.opt.type", FT_UINT8, BASE_HEX | BASE_EXT_STRING, &ipv6_opt_type_vals_ext, 0x0, "Option type", HFILL } }, { &hf_ipv6_opt_type_action, { "Action", "ipv6.opt.type.action", FT_UINT8, BASE_DEC, VALS(ipv6_opt_type_action_vals), 0xC0, "Action for unrecognized option type", HFILL } }, { &hf_ipv6_opt_type_change, { "May Change", "ipv6.opt.type.change", FT_BOOLEAN, 8, TFS(&tfs_yes_no), 0x20, "Whether the option data may change en-route", HFILL } }, { &hf_ipv6_opt_type_rest, { "Low-Order Bits", "ipv6.opt.type.rest", FT_UINT8, BASE_HEX, NULL, 0x1F, "Remaining low-order bits", HFILL } }, { &hf_ipv6_opt_length, { "Length", "ipv6.opt.length", FT_UINT8, BASE_DEC, NULL, 0x0, "Option length in octets", HFILL } }, { &hf_ipv6_opt_pad1, { "Pad1", "ipv6.opt.pad1", FT_NONE, BASE_NONE, NULL, 0x0, "Pad1 Option", HFILL } }, { &hf_ipv6_opt_padn, { "PadN", "ipv6.opt.padn", FT_BYTES, BASE_NONE|BASE_ALLOW_ZERO, NULL, 0x0, "PadN Option", HFILL } }, { &hf_ipv6_opt_pmtu_min, { "Minimum Reported PMTU", "ipv6.opt.pmtu.min", FT_UINT16, BASE_DEC, NULL, 0x0, "The minimum reported PMTU in octets", HFILL } }, { &hf_ipv6_opt_pmtu_rtn, { "Return Minimum PMTU", "ipv6.opt.pmtu.rtn", FT_UINT16, BASE_DEC, NULL, 0x0, "The Return Min-PMTU in octets", HFILL } }, { &hf_ipv6_opt_pmtu_rtn_flag, { "Return Flag", "ipv6.opt.pmtu.r_flag", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Destination should include the received reported PMTU", HFILL } }, { &hf_ipv6_opt_apn_id_type, { "ID Type", "ipv6.opt.apn.id.type", FT_UINT8, BASE_DEC, VALS(apn_id_type_strs), 0x0, "The type of the APN ID", HFILL } }, { &hf_ipv6_opt_apn_flags, { "Flags", "ipv6.opt.apn.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "Flags for advanced processing", HFILL } }, { &hf_ipv6_opt_apn_param_type, { "Parameters Types", "ipv6.opt.apn.param.type", FT_UINT16, BASE_HEX, NULL, 0x0, "Bitmap to identify the existence of APN Parameters", HFILL } }, { &hf_ipv6_opt_apn_id_part1, { "ID Part1", "ipv6.opt.apn.id.part1", FT_UINT32, BASE_HEX, NULL, 0x0, "The first 32-bit of the APN ID", HFILL } }, { &hf_ipv6_opt_apn_id_part2, { "ID Part2", "ipv6.opt.apn.id.part2", FT_UINT32, BASE_HEX, NULL, 0x0, "The second 32-bit of the APN ID", HFILL } }, { &hf_ipv6_opt_apn_id_part3, { "ID Part3", "ipv6.opt.apn.id.part3", FT_UINT32, BASE_HEX, NULL, 0x0, "The third 32-bit of the APN ID", HFILL } }, { &hf_ipv6_opt_apn_id_part4, { "ID Part4", "ipv6.opt.apn.id.part4", FT_UINT32, BASE_HEX, NULL, 0x0, "The last 32-bit of the APN ID", HFILL } }, { &hf_ipv6_opt_rtalert, { "Router Alert", "ipv6.opt.router_alert", FT_UINT16, BASE_DEC, VALS(ipv6_opt_rtalert_vals), 0x0, "Router Alert Option", HFILL } }, { &hf_ipv6_opt_tel, { "Tunnel Encapsulation Limit", "ipv6.opt.tel", FT_UINT8, BASE_DEC, NULL, 0x0, "How many further levels of encapsulation are permitted", HFILL } }, { &hf_ipv6_opt_jumbo, { "Payload Length", "ipv6.opt.jumbo", FT_UINT32, BASE_DEC, NULL, 0x0, "IPv6 (Jumbo) Payload Length", HFILL } }, { &hf_ipv6_opt_calipso_doi, { "CALIPSO Domain of Interpretation", "ipv6.opt.calipso.doi", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_calipso_cmpt_length, { "Compartment Length", "ipv6.opt.calipso.cmpt.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_calipso_sens_level, { "Sensitivity Level", "ipv6.opt.calipso.sens_level", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_calipso_checksum, { "Checksum", "ipv6.opt.calipso.checksum", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_calipso_cmpt_bitmap, { "Compartment Bitmap", "ipv6.opt.calipso.cmpt_bitmap", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_smf_dpd_hash_bit, { "H-bit", "ipv6.opt.smf_dpd.hash_bit", FT_BOOLEAN, 8, NULL, 0x80, "Hash indicator", HFILL } }, { &hf_ipv6_opt_smf_dpd_tid_type, { "TaggerID Type", "ipv6.opt.smf_dpd.tid_type", FT_UINT8, BASE_DEC, VALS(ipv6_opt_smf_dpd_tidty_vals), 0x70, NULL, HFILL } }, { &hf_ipv6_opt_smf_dpd_tid_len, { "TaggerID Length", "ipv6.opt.smf_dpd.tid_len", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL } }, { &hf_ipv6_opt_smf_dpd_tagger_id, { "TaggerID", "ipv6.opt.smf_dpd.tagger_id", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_smf_dpd_ident, { "Identifier", "ipv6.opt.smf_dpd.ident", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_smf_dpd_hav, { "Hash Assist Value", "ipv6.opt.smf_dpd.hav", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_pdm_scale_dtlr, { "Scale DTLR", "ipv6.opt.pdm.scale_dtlr", FT_UINT8, BASE_DEC, NULL, 0x0, "Scale for Delta Time Last Received", HFILL } }, { &hf_ipv6_opt_pdm_scale_dtls, { "Scale DTLS", "ipv6.opt.pdm.scale_dtls", FT_UINT8, BASE_DEC, NULL, 0x0, "Scale for Delta Time Last Sent", HFILL } }, { &hf_ipv6_opt_pdm_psn_this_pkt, { "PSN This Packet", "ipv6.opt.pdm.psn_this_pkt", FT_UINT16, BASE_DEC, NULL, 0x0, "Packet Sequence Number This Packet", HFILL } }, { &hf_ipv6_opt_pdm_psn_last_recv, { "PSN Last Received", "ipv6.opt.pdm.psn_last_recv", FT_UINT16, BASE_DEC, NULL, 0x0, "Packet Sequence Number Last Received", HFILL } }, { &hf_ipv6_opt_pdm_delta_last_recv, { "Delta Time Last Received", "ipv6.opt.pdm.delta_last_recv", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_pdm_delta_last_sent, { "Delta Time Last Sent", "ipv6.opt.pdm.delta_last_sent", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_qs_func, { "Function", "ipv6.opt.qs_func", FT_UINT8, BASE_DEC, VALS(qs_func_vals), QS_FUNC_MASK, NULL, HFILL } }, { &hf_ipv6_opt_qs_rate, { "Rate", "ipv6.opt.qs_rate", FT_UINT8, BASE_DEC | BASE_EXT_STRING, &qs_rate_vals_ext, QS_RATE_MASK, NULL, HFILL } }, { &hf_ipv6_opt_qs_ttl, { "QS TTL", "ipv6.opt.qs_ttl", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_qs_ttl_diff, { "TTL Diff", "ipv6.opt.qs_ttl_diff", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_qs_unused, { "Not Used", "ipv6.opt.qs_unused", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_qs_nonce, { "QS Nonce", "ipv6.opt.qs_nonce", FT_UINT32, BASE_HEX, NULL, 0xFFFFFFFC, NULL, HFILL } }, { &hf_ipv6_opt_qs_reserved, { "Reserved", "ipv6.opt.qs_reserved", FT_UINT32, BASE_HEX, NULL, 0x0003, NULL, HFILL } }, { &hf_ipv6_opt_ioam_rsv, { "Reserved", "ipv6.opt.ioam.rsv", FT_UINT8, BASE_DEC, NULL, 0x0, "Reserved (must be zero)", HFILL } }, { &hf_ipv6_opt_ioam_opt_type, { "Option-Type", "ipv6.opt.ioam.opt_type", FT_UINT8, BASE_DEC, VALS(ipv6_ioam_opt_types), 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_ns, { "Namespace ID", "ipv6.opt.ioam.trace.ns", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_nodelen, { "Node Length", "ipv6.opt.ioam.trace.nodelen", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_flags, { "Flags", "ipv6.opt.ioam.trace.flags", FT_UINT16, BASE_HEX, NULL, 0x0780, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_flag_o, { "Overflow", "ipv6.opt.ioam.trace.flag.o", FT_BOOLEAN, 16, NULL, 0x0400, "Not enough free space", HFILL } }, { &hf_ipv6_opt_ioam_trace_flag_l, { "Loopback", "ipv6.opt.ioam.trace.flag.l", FT_BOOLEAN, 16, NULL, 0x0200, "Send a copy of the packet back towards the source", HFILL } }, { &hf_ipv6_opt_ioam_trace_flag_a, { "Active", "ipv6.opt.ioam.trace.flag.a", FT_BOOLEAN, 16, NULL, 0x0100, "Active measurement packet", HFILL } }, { &hf_ipv6_opt_ioam_trace_flag_rsv, { "Reserved", "ipv6.opt.ioam.trace.flag.rsv", FT_BOOLEAN, 16, NULL, 0x0080, "Reserved (must be zero)", HFILL } }, { &hf_ipv6_opt_ioam_trace_remlen, { "Remaining Length", "ipv6.opt.ioam.trace.remlen", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type, { "Trace Type", "ipv6.opt.ioam.trace.type", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit0, { "Hop_Lim and Node ID (short)", "ipv6.opt.ioam.trace.type.bit0", FT_BOOLEAN, 24, NULL, 0x800000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit1, { "Ingress and Egress IDs (short)", "ipv6.opt.ioam.trace.type.bit1", FT_BOOLEAN, 24, NULL, 0x400000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit2, { "Timestamp seconds", "ipv6.opt.ioam.trace.type.bit2", FT_BOOLEAN, 24, NULL, 0x200000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit3, { "Timestamp fraction", "ipv6.opt.ioam.trace.type.bit3", FT_BOOLEAN, 24, NULL, 0x100000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit4, { "Transit delay", "ipv6.opt.ioam.trace.type.bit4", FT_BOOLEAN, 24, NULL, 0x080000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit5, { "IOAM-Namespace specific data (short)", "ipv6.opt.ioam.trace.type.bit5", FT_BOOLEAN, 24, NULL, 0x040000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit6, { "Queue depth", "ipv6.opt.ioam.trace.type.bit6", FT_BOOLEAN, 24, NULL, 0x020000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit7, { "Checksum complement", "ipv6.opt.ioam.trace.type.bit7", FT_BOOLEAN, 24, NULL, 0x010000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit8, { "Hop_Lim and Node ID (wide)", "ipv6.opt.ioam.trace.type.bit8", FT_BOOLEAN, 24, NULL, 0x008000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit9, { "Ingress and Egress IDs (wide)", "ipv6.opt.ioam.trace.type.bit9", FT_BOOLEAN, 24, NULL, 0x004000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit10, { "IOAM-Namespace specific data (wide)", "ipv6.opt.ioam.trace.type.bit10", FT_BOOLEAN, 24, NULL, 0x002000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit11, { "Buffer occupancy", "ipv6.opt.ioam.trace.type.bit11", FT_BOOLEAN, 24, NULL, 0x001000, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_undef, { "Undefined", "ipv6.opt.ioam.trace.type.undef", FT_BOOLEAN, 24, NULL, 0x000ffc, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_bit22, { "Opaque State Snapshot", "ipv6.opt.ioam.trace.type.bit22", FT_BOOLEAN, 24, NULL, 0x000002, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_type_rsv, { "Reserved", "ipv6.opt.ioam.trace.type.rsv", FT_BOOLEAN, 24, NULL, 0x000001, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_rsv, { "Reserved", "ipv6.opt.ioam.trace.rsv", FT_UINT8, BASE_DEC, NULL, 0x0, "Reserved (must be zero)", HFILL } }, { &hf_ipv6_opt_ioam_trace_free_space, { "Free space", "ipv6.opt.ioam.trace.free_space", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_hlim, { "Hop Limit", "ipv6.opt.ioam.trace.node.hlim", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_id, { "ID", "ipv6.opt.ioam.trace.node.id", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_iif, { "Ingress ID", "ipv6.opt.ioam.trace.node.iif", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_eif, { "Egress ID", "ipv6.opt.ioam.trace.node.eif", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_tss, { "Timestamp Seconds", "ipv6.opt.ioam.trace.node.tss", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_tsf, { "Timestamp Fraction", "ipv6.opt.ioam.trace.node.tsf", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_trdelay, { "Transit Delay", "ipv6.opt.ioam.trace.node.trdelay", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_nsdata, { "Namespace Data (short)", "ipv6.opt.ioam.trace.node.nsdata", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_qdepth, { "Queue Depth", "ipv6.opt.ioam.trace.node.qdepth", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_csum, { "Checksum Complement", "ipv6.opt.ioam.trace.node.csum", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_id_wide, { "ID", "ipv6.opt.ioam.trace.node.id_wide", FT_UINT56, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_iif_wide, { "Ingress ID", "ipv6.opt.ioam.trace.node.iif_wide", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_eif_wide, { "Egress ID", "ipv6.opt.ioam.trace.node.eif_wide", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_nsdata_wide, { "Namespace Data (wide)", "ipv6.opt.ioam.trace.node.nsdata_wide", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_bufoccup, { "Buffer Occupancy", "ipv6.opt.ioam.trace.node.bufoccup", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_undefined, { "Undefined bit", "ipv6.opt.ioam.trace.node.undefined", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_oss_len, { "Length", "ipv6.opt.ioam.trace.node.oss.len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_oss_scid, { "Schema ID", "ipv6.opt.ioam.trace.node.oss.scid", FT_UINT24, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_ioam_trace_node_oss_data, { "Data", "ipv6.opt.ioam.trace.node.oss.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_tpf_information, { "TPF Information", "ipv6.opt.tpf_information", FT_UINT32, BASE_HEX, NULL, 0x0, "Tunnel Payload Forwarding Information", HFILL } }, { &hf_ipv6_opt_mipv6_home_address, { "MIPv6 Home Address", "ipv6.opt.mipv6.home_address", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_rpl_flag, { "Flag", "ipv6.opt.rpl.flag", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_rpl_flag_o, { "Down", "ipv6.opt.rpl.flag.o", FT_BOOLEAN, 8, NULL, 0x80, "The packet is expected to progress Up or Down", HFILL } }, { &hf_ipv6_opt_rpl_flag_r, { "Rank Error", "ipv6.opt.rpl.flag.r", FT_BOOLEAN, 8, NULL, 0x40, "Whether a rank error was detected", HFILL } }, { &hf_ipv6_opt_rpl_flag_f, { "Forwarding Error", "ipv6.opt.rpl.flag.f", FT_BOOLEAN, 8, NULL, 0x20, "Set if the node cannot forward the packet further towards the destination", HFILL } }, { &hf_ipv6_opt_rpl_flag_rsv, { "Reserved", "ipv6.opt.rpl.flag.rsv", FT_UINT8, BASE_HEX, NULL, 0x1F, "Reserved (must be zero)", HFILL } }, { &hf_ipv6_opt_rpl_instance_id, { "RPLInstanceID", "ipv6.opt.rpl.instance_id", FT_UINT8, BASE_HEX, NULL, 0x0, "The DODAG instance along which the packet is sent", HFILL } }, { &hf_ipv6_opt_rpl_senderrank, { "Sender Rank", "ipv6.opt.rpl.sender_rank", FT_UINT16, BASE_HEX, NULL, 0x0, "Set to zero by the source and to DAGRank(rank) by a router that forwards inside the RPL network", HFILL } }, { &hf_ipv6_opt_ilnp_nonce, { "ILNP Nonce", "ipv6.opt.ilnp_nonce", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_lio_len, { "LineIDLen", "ipv6.opt.lio.length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_lio_id, { "Line ID", "ipv6.opt.lio.line_id", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_mpl_flag, { "Flag", "ipv6.opt.mpl.flag", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_mpl_flag_s, { "Seed ID Length", "ipv6.opt.mpl.flag.s", FT_UINT8, BASE_DEC, VALS(mpl_seed_id_len_vals), 0xC0, "Identifies the length of Seed ID", HFILL } }, { &hf_ipv6_opt_mpl_flag_m, { "Largest Sequence", "ipv6.opt.mpl.flag.m", FT_BOOLEAN, 8, NULL, 0x20, "Indicates Sequence is known to be the largest sequence number", HFILL } }, { &hf_ipv6_opt_mpl_flag_v, { "Version", "ipv6.opt.mpl.flag.v", FT_BOOLEAN, 8, NULL, 0x10, "0 indicates this option conforms to RFC", HFILL } }, { &hf_ipv6_opt_mpl_flag_rsv, { "Reserved", "ipv6.opt.mpl.flag.rsv", FT_UINT8, BASE_HEX, NULL, 0x0F, "Reserved (must be zero)", HFILL } }, { &hf_ipv6_opt_mpl_sequence, { "Sequence", "ipv6.opt.mpl.sequence", FT_UINT8, BASE_HEX, NULL, 0x0, "Identifies relative ordering of MPL Data Messages from the MPL Seed identified by Seed ID", HFILL } }, { &hf_ipv6_opt_mpl_seed_id, { "Seed ID", "ipv6.opt.mpl.seed_id", FT_BYTES, BASE_NONE, NULL, 0x0, "Uniquely identifies the MPL Seed that initiated dissemination of the MPL Data Message", HFILL } }, { &hf_ipv6_opt_dff_flags, { "Flags", "ipv6.opt.dff.flags", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_dff_flag_ver, { "Version (VER)", "ipv6.opt.dff.flag.ver", FT_UINT8, BASE_DEC, NULL, 0xC0, "The version of DFF that is used", HFILL } }, { &hf_ipv6_opt_dff_flag_dup, { "Duplicate (DUP)", "ipv6.opt.dff.flag.dup", FT_BOOLEAN, 8, NULL, 0x20, "Indicates the packet is being retransmitted", HFILL } }, { &hf_ipv6_opt_dff_flag_ret, { "Return (RET)", "ipv6.opt.dff.flag.ret", FT_BOOLEAN, 8, NULL, 0x10, "Must be set to 1 prior to sending the packet back to the Previous Hop", HFILL } }, { &hf_ipv6_opt_dff_flag_rsv, { "Reserved", "ipv6.opt.dff.flag.rsv", FT_UINT8, BASE_HEX, NULL, 0x0F, "Reserved (must be zero)", HFILL } }, { &hf_ipv6_opt_dff_seqnum, { "Sequence Number", "ipv6.opt.dff.sequence_number", FT_UINT16, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_experimental, { "Experimental Option", "ipv6.opt.experimental", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_opt_unknown_data, { "Unknown Data", "ipv6.opt_unknown_data", FT_BYTES, BASE_NONE, NULL, 0x0, "Not interpreted data", HFILL } }, { &hf_ipv6_opt_unknown, { "Unknown Option Payload", "ipv6.opt.unknown", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_fragment, { "IPv6 Fragment", "ipv6.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_fragment_overlap, { "Fragment overlap", "ipv6.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL } }, { &hf_ipv6_fragment_overlap_conflict, { "Conflicting data in fragment overlap", "ipv6.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Overlapping fragments contained conflicting data", HFILL } }, { &hf_ipv6_fragment_multiple_tails, { "Multiple tail fragments found", "ipv6.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Several tails were found when defragmenting the packet", HFILL } }, { &hf_ipv6_fragment_too_long_fragment, { "Fragment too long", "ipv6.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment contained data past end of packet", HFILL } }, { &hf_ipv6_fragment_error, { "Defragmentation error", "ipv6.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "Defragmentation error due to illegal fragments", HFILL } }, { &hf_ipv6_fragment_count, { "Fragment count", "ipv6.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_fragments, { "IPv6 Fragments", "ipv6.fragments", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } }, { &hf_ipv6_reassembled_in, { "Reassembled IPv6 in frame", "ipv6.reassembled.in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "This IPv6 packet is reassembled in this frame", HFILL } }, { &hf_ipv6_reassembled_length, { "Reassembled IPv6 length", "ipv6.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0, "The total length of the reassembled payload", HFILL } }, { &hf_ipv6_reassembled_data, { "Reassembled IPv6 data", "ipv6.reassembled.data", FT_BYTES, BASE_NONE, NULL, 0x0, "The reassembled payload", HFILL } } }; static hf_register_info hf_ipv6_hopopts[] = { { &hf_ipv6_hopopts_nxt, { "Next Header", "ipv6.hopopts.nxt", FT_UINT8, BASE_DEC | BASE_EXT_STRING, &ipproto_val_ext, 0x0, NULL, HFILL } }, { &hf_ipv6_hopopts_len, { "Length", "ipv6.hopopts.len", FT_UINT8, BASE_DEC, NULL, 0x0, "Extension header length in 8-octet words (minus 1)", HFILL } }, { &hf_ipv6_hopopts_len_oct, { "Length", "ipv6.hopopts.len_oct", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0, "Extension header length in octets", HFILL } } }; static hf_register_info hf_ipv6_dstopts[] = { { &hf_ipv6_dstopts_nxt, { "Next Header", "ipv6.dstopts.nxt", FT_UINT8, BASE_DEC | BASE_EXT_STRING, &ipproto_val_ext, 0x0, NULL, HFILL } }, { &hf_ipv6_dstopts_len, { "Length", "ipv6.dstopts.len", FT_UINT8, BASE_DEC, NULL, 0x0, "Extension header length in 8-octet words (minus 1)", HFILL } }, { &hf_ipv6_dstopts_len_oct, { "Length", "ipv6.dstopts.len_oct", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0, "Extension header length in octets", HFILL } } }; static hf_register_info hf_ipv6_routing[] = { /* IPv6 Routing Header */ { &hf_ipv6_routing_nxt, { "Next Header", "ipv6.routing.nxt", FT_UINT8, BASE_DEC | BASE_EXT_STRING, &ipproto_val_ext, 0x0, NULL, HFILL } }, { &hf_ipv6_routing_len, { "Length", "ipv6.routing.len", FT_UINT8, BASE_DEC, NULL, 0x0, "Extension header length in 8-octet words (minus 1)", HFILL } }, { &hf_ipv6_routing_len_oct, { "Length", "ipv6.routing.len_oct", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0, "Extension header length in octets", HFILL } }, { &hf_ipv6_routing_type, { "Type", "ipv6.routing.type", FT_UINT8, BASE_DEC, VALS(routing_header_type), 0x0, "Routing Header Type", HFILL } }, { &hf_ipv6_routing_segleft, { "Segments Left", "ipv6.routing.segleft", FT_UINT8, BASE_DEC, NULL, 0x0, "Routing Header Segments Left", HFILL } }, { &hf_ipv6_routing_unknown_data, { "Type-Specific Data", "ipv6.routing.unknown_data", FT_BYTES, BASE_NONE, NULL, 0x0, "Unknown routing header type-specific data", HFILL } }, /* Source Routing Header */ { &hf_ipv6_routing_src_reserved, { "Reserved", "ipv6.routing.src.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, "Must be zero", HFILL } }, { &hf_ipv6_routing_src_addr, { "Address", "ipv6.routing.src.addr", FT_IPv6, BASE_NONE, NULL, 0x0, "Source Routing Header Address", HFILL }}, /* Mobile IPv6 */ { &hf_ipv6_routing_mipv6_reserved, { "Reserved", "ipv6.routing.mipv6.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, "Must be zero", HFILL } }, { &hf_ipv6_routing_mipv6_home_address, { "Home Address", "ipv6.routing.mipv6.home_address", FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL } }, /* RPL Routing Header */ { &hf_ipv6_routing_rpl_cmprI, { "Compressed Internal Octets (CmprI)", "ipv6.routing.rpl.cmprI", FT_UINT32, BASE_DEC, NULL, IP6RRPL_BITMASK_CMPRI, "Elided octets from all but last segment", HFILL } }, { &hf_ipv6_routing_rpl_cmprE, { "Compressed Final Octets (CmprE)", "ipv6.routing.rpl.cmprE", FT_UINT32, BASE_DEC, NULL, IP6RRPL_BITMASK_CMPRE, "Elided octets from last segment address", HFILL } }, { &hf_ipv6_routing_rpl_pad, { "Padding Bytes", "ipv6.routing.rpl.pad", FT_UINT32, BASE_DEC, NULL, IP6RRPL_BITMASK_PAD, NULL, HFILL } }, { &hf_ipv6_routing_rpl_reserved, { "Reserved", "ipv6.routing.rpl.reserved", FT_UINT32, BASE_DEC, NULL, IP6RRPL_BITMASK_RESERVED, "Must be zero", HFILL } }, { &hf_ipv6_routing_rpl_addr_count, { "Total Address Count", "ipv6.routing.rpl.addr_count", FT_INT32, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_ipv6_routing_rpl_addr, { "Address", "ipv6.routing.rpl.address", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_ipv6_routing_rpl_fulladdr, { "Full Address", "ipv6.routing.rpl.full_address", FT_IPv6, BASE_NONE, NULL, 0, "Uncompressed IPv6 Address", HFILL } }, /* Segment Routing Header */ { &hf_ipv6_routing_srh_last_entry, { "Last Entry", "ipv6.routing.srh.last_entry", FT_UINT8, BASE_DEC, NULL, 0x0, "Index (zero based) of the last element of the Segment List", HFILL } }, { &hf_ipv6_routing_srh_flags, { "Flags", "ipv6.routing.srh.flags", FT_UINT8, BASE_HEX, NULL, 0x0, "Unused, 8 bits of flags", HFILL } }, { &hf_ipv6_routing_srh_tag, { "Tag", "ipv6.routing.srh.tag", FT_BYTES, BASE_NONE, NULL, 0x0, "Tag a packet as part of a class or group of packets", HFILL } }, { &hf_ipv6_routing_srh_addr, { "Address", "ipv6.routing.srh.addr", FT_IPv6, BASE_NONE, NULL, 0x0, "Segment address", HFILL } }, /* Compact Routing Header */ { &hf_ipv6_routing_crh16_current_sid, { "Current SID", "ipv6.routing.crh16.current_sid", FT_UINT16, BASE_DEC, NULL, 0x0, "Value of the current Segment ID", HFILL } }, { &hf_ipv6_routing_crh32_current_sid, { "Current SID", "ipv6.routing.crh32.current_sid", FT_UINT32, BASE_DEC, NULL, 0x0, "Value of the current Segment ID", HFILL } }, { &hf_ipv6_routing_crh16_segment_id, { "Segment ID", "ipv6.routing.crh16.sid", FT_UINT16, BASE_DEC, NULL, 0x0, "Segment address", HFILL } }, { &hf_ipv6_routing_crh32_segment_id, { "Segment ID", "ipv6.routing.crh32.sid", FT_UINT32, BASE_DEC, NULL, 0x0, "Segment address", HFILL } } }; static hf_register_info hf_ipv6_fraghdr[] = { { &hf_ipv6_fraghdr_nxt, { "Next header", "ipv6.fraghdr.nxt", FT_UINT8, BASE_DEC | BASE_EXT_STRING, &ipproto_val_ext, 0x0, NULL, HFILL } }, { &hf_ipv6_fraghdr_reserved_octet, { "Reserved octet", "ipv6.fraghdr.reserved_octet", FT_UINT8, BASE_HEX, NULL, 0x0, "Should always be 0", HFILL } }, { &hf_ipv6_fraghdr_offset, { "Offset", "ipv6.fraghdr.offset", FT_UINT16, BASE_DEC, NULL, IP6F_OFF_MASK, "Fragment Offset", HFILL } }, { &hf_ipv6_fraghdr_reserved_bits, { "Reserved bits", "ipv6.fraghdr.reserved_bits", FT_UINT16, BASE_DEC, NULL, IP6F_RESERVED_MASK, NULL, HFILL } }, { &hf_ipv6_fraghdr_more, { "More Fragments", "ipv6.fraghdr.more", FT_BOOLEAN, 16, TFS(&tfs_yes_no), IP6F_MORE_FRAG, NULL, HFILL } }, { &hf_ipv6_fraghdr_ident, { "Identification", "ipv6.fraghdr.ident", FT_UINT32, BASE_HEX, NULL, 0x0, "Fragment Identification", HFILL } } }; static gint *ett_ipv6[] = { &ett_ipv6_proto, &ett_ipv6_detail, &ett_ipv6_multicast_flags, &ett_ipv6_traffic_class, &ett_geoip_info, &ett_ipv6_opt, &ett_ipv6_opt_type, &ett_ipv6_opt_rpl, &ett_ipv6_opt_mpl, &ett_ipv6_opt_dff_flags, &ett_ipv6_opt_ioam_trace_flags, &ett_ipv6_opt_ioam_trace_types, &ett_ipv6_fragment, &ett_ipv6_fragments }; static gint *ett_ipv6_hopopts[] = { &ett_ipv6_hopopts_proto }; static gint *ett_ipv6_routing[] = { &ett_ipv6_routing_proto, &ett_ipv6_routing_srh_vect }; static gint *ett_ipv6_fraghdr[] = { &ett_ipv6_fraghdr_proto }; static gint *ett_ipv6_dstopts[] = { &ett_ipv6_dstopts_proto }; static ei_register_info ei_ipv6[] = { { &ei_ipv6_opt_jumbo_missing, { "ipv6.opt.jumbo.missing", PI_MALFORMED, PI_ERROR, "IPv6 payload length equals 0 and Hop-By-Hop present and Jumbo Payload option missing", EXPFILL } }, { &ei_ipv6_opt_jumbo_prohibited, { "ipv6.opt.jumbo.prohibited", PI_PROTOCOL, PI_WARN, "When IPv6 payload length does not equal 0 a Jumbo Payload option must not be present", EXPFILL } }, { &ei_ipv6_opt_jumbo_truncated, { "ipv6.opt.jumbo.truncated", PI_PROTOCOL, PI_WARN, "Jumbo Payload option present and jumbo length < 65536", EXPFILL } }, { &ei_ipv6_opt_jumbo_fragment, { "ipv6.opt.jumbo.fragment", PI_PROTOCOL, PI_WARN, "Jumbo Payload option cannot be used with a fragment header", EXPFILL } }, { &ei_ipv6_opt_invalid_len, { "ipv6.opt.invalid_len", PI_MALFORMED, PI_ERROR, "Invalid IPv6 option length", EXPFILL } }, { &ei_ipv6_opt_apn_invalid_id_type, { "ipv6.opt.apn.invalid.id_type", PI_MALFORMED, PI_ERROR, "Invalid APN ID Type", EXPFILL } }, { &ei_ipv6_opt_unknown_data, { "ipv6.opt.unknown_data.expert", PI_UNDECODED, PI_NOTE, "Unknown Data (not interpreted)", EXPFILL } }, { &ei_ipv6_plen_exceeds_framing, { "ipv6.plen_exceeds_framing", PI_PROTOCOL, PI_WARN, "IPv6 payload length does not match expected framing length", EXPFILL } }, { &ei_ipv6_plen_zero, { "ipv6.plen_zero", PI_PROTOCOL, PI_CHAT, "IPv6 payload length equals 0 (maybe because of \"TCP segmentation offload\" (TSO))", EXPFILL } }, { &ei_ipv6_bogus_ipv6_version, { "ipv6.bogus_ipv6_version", PI_MALFORMED, PI_ERROR, "Bogus IP version", EXPFILL } }, { &ei_ipv6_invalid_header, { "ipv6.invalid_header", PI_MALFORMED, PI_ERROR, "Invalid IPv6 header", EXPFILL } }, { &ei_ipv6_opt_header_mismatch, { "ipv6.opt.header_mismatch", PI_PROTOCOL, PI_WARN, "Wrong options extension header for type", EXPFILL } }, { &ei_ipv6_opt_deprecated, { "ipv6.opt.deprecated", PI_DEPRECATED, PI_NOTE, "Option type is deprecated", EXPFILL } }, { &ei_ipv6_opt_mpl_ipv6_src_seed_id, { "ipv6.opt.mpl.ipv6_src_seed_id", PI_PROTOCOL, PI_COMMENT, "Seed ID is the IPv6 Source Address", EXPFILL } }, { &ei_ipv6_opt_ioam_invalid_nodelen, { "ipv6.opt.ioam.trace.invalid_nodelen", PI_PROTOCOL, PI_ERROR, "Invalid \"NodeLen\" value: cannot be 0", EXPFILL } }, { &ei_ipv6_opt_ioam_invalid_remlen, { "ipv6.opt.ioam.trace.invalid_remlen", PI_PROTOCOL, PI_ERROR, "Invalid \"RemLen\" value", EXPFILL } }, { &ei_ipv6_opt_ioam_invalid_trace_type, { "ipv6.opt.ioam.trace.invalid_type", PI_PROTOCOL, PI_ERROR, "Mismatch between Trace Type and NodeLen", EXPFILL } }, { &ei_ipv6_embed_ipv4_u_value, { "ipv6.embed_ipv4.u.nonzero", PI_PROTOCOL, PI_WARN, "IPv4-Embedded IPv6 address bit 64 to 71 must be zero", EXPFILL } }, { &ei_ipv6_dst_addr_not_unspecified, { "ipv6.addr.not_unspecified", PI_PROTOCOL, PI_WARN, "Unspecified address cannot appear as a destination", EXPFILL } } }; static ei_register_info ei_ipv6_hopopts[] = { { &ei_ipv6_hopopts_not_first, { "ipv6.hopopts.not_first", PI_PROTOCOL, PI_ERROR, "IPv6 Hop-by-Hop extension header must appear immediately after IPv6 header", EXPFILL } } }; static ei_register_info ei_ipv6_routing[] = { { &ei_ipv6_src_addr_not_multicast, { "ipv6.src_addr.not_multicast", PI_PROTOCOL, PI_WARN, "Source address must not be a multicast address", EXPFILL } }, { &ei_ipv6_dst_addr_not_multicast, { "ipv6.dst_addr.not_multicast", PI_PROTOCOL, PI_WARN, "Destination address must not be a multicast address", EXPFILL } }, { &ei_ipv6_src_route_list_mult_inst_same_addr, { "ipv6.src_route_list.mult_inst_same_addr", PI_PROTOCOL, PI_WARN, "Multiple instances of the same address must not appear in the source route list", EXPFILL } }, { &ei_ipv6_src_route_list_src_addr, { "ipv6.src_route_list.src_addr", PI_PROTOCOL, PI_WARN, "Source address must not appear in the source route list", EXPFILL } }, { &ei_ipv6_src_route_list_dst_addr, { "ipv6.src_route_list.dst_addr", PI_PROTOCOL, PI_WARN, "Destination address must not appear in the source route list", EXPFILL } }, { &ei_ipv6_src_route_list_multicast_addr, { "ipv6.src_route_list.multicast_addr", PI_PROTOCOL, PI_WARN, "Multicast addresses must not appear in the source route list", EXPFILL } }, { &ei_ipv6_routing_rpl_cmpri_cmpre_pad, { "ipv6.routing.rpl.cmprI_cmprE_pad", PI_PROTOCOL, PI_WARN, "When cmprI equals 0 and cmprE equals 0, pad MUST equal 0 but instead was X", EXPFILL } }, { &ei_ipv6_routing_rpl_addr_count_ge0, { "ipv6.routing.rpl.addr_count_ge0", PI_MALFORMED, PI_ERROR, "Calculated total address count must be greater than or equal to 0, instead was X", EXPFILL } }, { &ei_ipv6_routing_rpl_reserved, { "ipv6.routing.rpl.reserved_not0", PI_PROTOCOL, PI_NOTE, "Reserved field must equal 0 but instead was X", EXPFILL } }, { &ei_ipv6_routing_invalid_length, { "ipv6.routing.invalid_length", PI_MALFORMED, PI_ERROR, "Invalid IPv6 Routing header length", EXPFILL } }, { &ei_ipv6_routing_invalid_segleft, { "ipv6.routing.invalid_segleft", PI_PROTOCOL, PI_WARN, "IPv6 Routing Header segments left field must not exceed address count", EXPFILL } }, { &ei_ipv6_routing_undecoded, { "ipv6.routing.undecoded", PI_UNDECODED, PI_NOTE, "Undecoded IPv6 routing header field", EXPFILL } }, { &ei_ipv6_routing_deprecated, { "ipv6.routing.deprecated", PI_DEPRECATED, PI_NOTE, "Routing header type is deprecated", EXPFILL } } }; /* Decode As handling */ static build_valid_func ipv6_da_build_value[1] = {ipv6_value}; static decode_as_value_t ipv6_da_values = {ipv6_prompt, 1, ipv6_da_build_value}; static decode_as_t ipv6_da = {"ipv6", "ip.proto", 1, 0, &ipv6_da_values, NULL, NULL, decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL}; static decode_as_t ipv6_hopopts_da = {"ipv6.hopopts", "ip.proto", 1, 0, &ipv6_da_values, NULL, NULL, decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL}; static decode_as_t ipv6_routing_da = {"ipv6.routing", "ip.proto", 1, 0, &ipv6_da_values, NULL, NULL, decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL}; static decode_as_t ipv6_fraghdr_da = {"ipv6.fraghdr", "ip.proto", 1, 0, &ipv6_da_values, NULL, NULL, decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL}; static decode_as_t ipv6_dstopts_da = {"ipv6.dstopts", "ip.proto", 1, 0, &ipv6_da_values, NULL, NULL, decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL}; module_t *ipv6_module; expert_module_t* expert_ipv6; expert_module_t* expert_ipv6_hopopts; expert_module_t* expert_ipv6_routing; proto_ipv6 = proto_register_protocol("Internet Protocol Version 6", "IPv6", "ipv6"); proto_register_field_array(proto_ipv6, hf_ipv6, array_length(hf_ipv6)); proto_register_subtree_array(ett_ipv6, array_length(ett_ipv6)); expert_ipv6 = expert_register_protocol(proto_ipv6); expert_register_field_array(expert_ipv6, ei_ipv6, array_length(ei_ipv6)); proto_ipv6_hopopts = proto_register_protocol("IPv6 Hop-by-Hop Option", "IPv6 Hop-by-Hop", "ipv6.hopopts"); proto_register_field_array(proto_ipv6_hopopts, hf_ipv6_hopopts, array_length(hf_ipv6_hopopts)); proto_register_subtree_array(ett_ipv6_hopopts, array_length(ett_ipv6_hopopts)); expert_ipv6_hopopts = expert_register_protocol(proto_ipv6_hopopts); expert_register_field_array(expert_ipv6_hopopts, ei_ipv6_hopopts, array_length(ei_ipv6_hopopts)); proto_ipv6_routing = proto_register_protocol("Routing Header for IPv6", "IPv6 Routing", "ipv6.routing"); proto_register_field_array(proto_ipv6_routing, hf_ipv6_routing, array_length(hf_ipv6_routing)); proto_register_subtree_array(ett_ipv6_routing, array_length(ett_ipv6_routing)); expert_ipv6_routing = expert_register_protocol(proto_ipv6_routing); expert_register_field_array(expert_ipv6_routing, ei_ipv6_routing, array_length(ei_ipv6_routing)); ipv6_routing_dissector_table = register_dissector_table("ipv6.routing.type", "IPv6 Routing Type", proto_ipv6_routing, FT_UINT8, BASE_DEC); proto_ipv6_routing_rt0 = proto_register_protocol_in_name_only("IPv6 Routing Type - Source Route", "Source Route", "ipv6.routing.type.rt0", proto_ipv6, FT_BYTES); proto_ipv6_routing_mipv6 = proto_register_protocol_in_name_only("IPv6 Routing Type - Type 2", "Type 2", "ipv6.routing.type.mipv6", proto_ipv6, FT_BYTES); proto_ipv6_routing_rpl = proto_register_protocol_in_name_only("IPv6 Routing Type - RPL Source Route", "RPL Source Route", "ipv6.routing.type.mipv6", proto_ipv6, FT_BYTES); proto_ipv6_routing_srh = proto_register_protocol_in_name_only("IPv6 Routing Types - Segment Routing", "Segment Routing", "ipv6.routing.type.srh", proto_ipv6, FT_BYTES); proto_ipv6_routing_crh = proto_register_protocol_in_name_only("IPv6 Routing Types - Compact Routing", "Compact Routing", "ipv6.routing.type.crh", proto_ipv6, FT_BYTES); proto_ipv6_fraghdr = proto_register_protocol("Fragment Header for IPv6", "IPv6 Fragment", "ipv6.fraghdr"); proto_register_field_array(proto_ipv6_fraghdr, hf_ipv6_fraghdr, array_length(hf_ipv6_fraghdr)); proto_register_subtree_array(ett_ipv6_fraghdr, array_length(ett_ipv6_fraghdr)); proto_ipv6_dstopts = proto_register_protocol("Destination Options for IPv6", "IPv6 Destination", "ipv6.dstopts"); proto_register_field_array(proto_ipv6_dstopts, hf_ipv6_dstopts, array_length(hf_ipv6_dstopts)); proto_register_subtree_array(ett_ipv6_dstopts, array_length(ett_ipv6_dstopts)); /* Register configuration options */ ipv6_module = prefs_register_protocol(proto_ipv6, NULL); prefs_register_bool_preference(ipv6_module, "defragment", "Reassemble fragmented IPv6 datagrams", "Whether fragmented IPv6 datagrams should be reassembled", &ipv6_reassemble); prefs_register_bool_preference(ipv6_module, "summary_in_tree", "Show IPv6 summary in protocol tree", "Whether the IPv6 summary line should be shown in the protocol tree", &ipv6_summary_in_tree); prefs_register_bool_preference(ipv6_module, "address_detail" , "Show details about IPv6 addresses", "Whether to show extended information about IPv6 addresses", &ipv6_address_detail); prefs_register_bool_preference(ipv6_module, "use_geoip" , "Enable IPv6 geolocation", "Whether to look up IPv6 addresses in each MaxMind database we have loaded", &ipv6_use_geoip); /* RPL Strict Header Checking */ prefs_register_bool_preference(ipv6_module, "perform_strict_rpl_srh_rfc_checking", "Perform strict checking for RPL Source Routing Headers (RFC 6554)", "Check that all RPL Source Routed packets conform to RFC 6554 and do not visit a node more than once", &g_ipv6_rpl_srh_strict_rfc_checking); prefs_register_bool_preference(ipv6_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_bool_preference(ipv6_module, "exthdr_under_root_protocol_tree", "Display IPv6 extension headers under the root protocol tree", "Whether to display IPv6 extension headers as a separate protocol or a sub-protocol of the IPv6 packet", &ipv6_exthdr_under_root); prefs_register_bool_preference(ipv6_module, "exthdr_hide_len_oct_field", "Use a single field for IPv6 extension header length", "If enabled the Length field in octets will be hidden", &ipv6_exthdr_hide_len_oct_field); prefs_register_bool_preference(ipv6_module, "tso_support", "Support packet-capture from IPv6 TSO-enabled hardware", "Whether to correct for TSO-enabled (TCP segmentation offload) hardware " "captures, such as spoofing the IPv6 packet length", &ipv6_tso_supported); static uat_field_t nat64_uats_flds[] = { UAT_FLD_CSTRING_OTHER(nat64_prefix_uats, ipaddr, "NAT64 Prefix", nat64_prefix_uat_fld_ip_chk_cb, "IPv6 prefix address"), UAT_FLD_VS(nat64_prefix_uats, prefix_len, "Prefix length", nat64_prefix_length_vals, "IPv6 prefix address length"), UAT_FLD_VS(nat64_prefix_uats, prefix_wildcard_len, "Prefix wildcard length", nat64_prefix_wildcard_length_vals, "IPv6 prefix address wildcard length"), UAT_END_FIELDS }; nat64_prefix_uat = uat_new("NAT64 Network-Specific Prefixes", sizeof(struct nat64_prefix_data), "NAT64_NSP_list", /* filename */ TRUE, /* from_profile */ &nat64_prefix_uats, /* data_ptr */ &number_of_nat64_prefix, /* numitems_ptr */ UAT_AFFECTS_DISSECTION, NULL, nat64_prefix_copy_cb, NULL, nat64_prefix_free_cb, NULL, NULL, nat64_uats_flds); prefs_register_uat_preference(ipv6_module, "nat64_prefixes", "NAT64 Prefixes", "A list of IPv6 prefixes used for NAT64s", nat64_prefix_uat); ipv6_handle = register_dissector("ipv6", dissect_ipv6, proto_ipv6); reassembly_table_register(&ipv6_reassembly_table, &addresses_reassembly_table_functions); ipv6_tap = register_tap("ipv6"); register_decode_as(&ipv6_da); register_decode_as(&ipv6_hopopts_da); register_decode_as(&ipv6_routing_da); register_decode_as(&ipv6_fraghdr_da); register_decode_as(&ipv6_dstopts_da); register_conversation_table(proto_ipv6, TRUE, ipv6_conversation_packet, ipv6_endpoint_packet); register_conversation_filter("ipv6", "IPv6", ipv6_filter_valid, ipv6_build_filter); register_capture_dissector("ipv6", capture_ipv6, proto_ipv6); } void proto_reg_handoff_ipv6(void) { dissector_handle_t ipv6_hopopts_handle; dissector_handle_t ipv6_routing_handle; dissector_handle_t ipv6_fraghdr_handle; dissector_handle_t ipv6_dstopts_handle; capture_dissector_handle_t ipv6_cap_handle; capture_dissector_handle_t ipv6_ext_cap_handle; dissector_handle_t h; dissector_add_uint("ethertype", ETHERTYPE_IPv6, ipv6_handle); dissector_add_uint("erf.types.type", ERF_TYPE_IPV6, ipv6_handle); dissector_add_uint("ppp.protocol", PPP_IPV6, ipv6_handle); dissector_add_uint("ppp.protocol", ETHERTYPE_IPv6, ipv6_handle); dissector_add_uint("gre.proto", ETHERTYPE_IPv6, ipv6_handle); dissector_add_uint("ip.proto", IP_PROTO_IPV6, ipv6_handle); dissector_add_uint("null.type", BSD_AF_INET6_BSD, ipv6_handle); dissector_add_uint("null.type", BSD_AF_INET6_FREEBSD, ipv6_handle); dissector_add_uint("null.type", BSD_AF_INET6_DARWIN, ipv6_handle); dissector_add_uint("chdlc.protocol", ETHERTYPE_IPv6, ipv6_handle); dissector_add_uint("fr.nlpid", NLPID_IP6, ipv6_handle); dissector_add_uint("osinl.excl", NLPID_IP6, ipv6_handle); dissector_add_uint("x.25.spi", NLPID_IP6, ipv6_handle); dissector_add_uint("arcnet.protocol_id", ARCNET_PROTO_IPv6, ipv6_handle); dissector_add_uint("juniper.proto", JUNIPER_PROTO_IP6, ipv6_handle); dissector_add_uint("juniper.proto", JUNIPER_PROTO_MPLS_IP6, ipv6_handle); dissector_add_uint("pwach.channel_type", PW_ACH_TYPE_IPV6, ipv6_handle); dissector_add_uint("mcc.proto", PW_ACH_TYPE_IPV6, ipv6_handle); dissector_add_uint("sflow_245.header_protocol", SFLOW_245_HEADER_IPv6, ipv6_handle); dissector_add_uint("wtap_encap", WTAP_ENCAP_RAW_IP6, ipv6_handle); dissector_add_uint("enc", BSD_AF_INET6_BSD, ipv6_handle); dissector_add_uint("vxlan.next_proto", VXLAN_IPV6, ipv6_handle); dissector_add_uint("nsh.next_proto", NSH_IPV6, ipv6_handle); dissector_add_for_decode_as_with_preference("udp.port", ipv6_handle); ipv6_hopopts_handle = create_dissector_handle(dissect_hopopts, proto_ipv6_hopopts); dissector_add_uint("ip.proto", IP_PROTO_HOPOPTS, ipv6_hopopts_handle); ipv6_routing_handle = create_dissector_handle(dissect_routing6, proto_ipv6_routing); dissector_add_uint("ip.proto", IP_PROTO_ROUTING, ipv6_routing_handle); ipv6_fraghdr_handle = create_dissector_handle(dissect_fraghdr, proto_ipv6_fraghdr); dissector_add_uint("ip.proto", IP_PROTO_FRAGMENT, ipv6_fraghdr_handle); ipv6_dstopts_handle = create_dissector_handle(dissect_dstopts, proto_ipv6_dstopts); dissector_add_uint("ip.proto", IP_PROTO_DSTOPTS, ipv6_dstopts_handle); ip_dissector_table = find_dissector_table("ip.proto"); ipv6_cap_handle = find_capture_dissector("ipv6"); capture_dissector_add_uint("ethertype", ETHERTYPE_IPv6, ipv6_cap_handle); capture_dissector_add_uint("enc", BSD_AF_INET6_BSD, ipv6_cap_handle); capture_dissector_add_uint("null.bsd", BSD_AF_INET6_BSD, ipv6_cap_handle); capture_dissector_add_uint("null.bsd", BSD_AF_INET6_FREEBSD, ipv6_cap_handle); capture_dissector_add_uint("null.bsd", BSD_AF_INET6_DARWIN, ipv6_cap_handle); capture_dissector_add_uint("fr.nlpid", NLPID_IP6, ipv6_cap_handle); ipv6_ext_cap_handle = create_capture_dissector_handle(capture_ipv6_exthdr, proto_ipv6_hopopts); capture_dissector_add_uint("ip.proto", IP_PROTO_HOPOPTS, ipv6_ext_cap_handle); ipv6_ext_cap_handle = create_capture_dissector_handle(capture_ipv6_exthdr, proto_ipv6_routing); capture_dissector_add_uint("ip.proto", IP_PROTO_ROUTING, ipv6_ext_cap_handle); ipv6_ext_cap_handle = create_capture_dissector_handle(capture_ipv6_exthdr, proto_ipv6_fraghdr); capture_dissector_add_uint("ip.proto", IP_PROTO_FRAGMENT, ipv6_ext_cap_handle); ipv6_ext_cap_handle = create_capture_dissector_handle(capture_ipv6_exthdr, proto_ipv6_dstopts); capture_dissector_add_uint("ip.proto", IP_PROTO_DSTOPTS, ipv6_ext_cap_handle); h = create_dissector_handle(dissect_routing6_rt0, proto_ipv6_routing_rt0); dissector_add_uint("ipv6.routing.type", IPv6_RT_HEADER_SOURCE_ROUTING, h); h = create_dissector_handle(dissect_routing6_mipv6, proto_ipv6_routing_mipv6); dissector_add_uint("ipv6.routing.type", IPv6_RT_HEADER_MOBILE_IP, h); h = create_dissector_handle(dissect_routing6_rpl, proto_ipv6_routing_rpl); dissector_add_uint("ipv6.routing.type", IPv6_RT_HEADER_RPL, h); h = create_dissector_handle(dissect_routing6_srh, proto_ipv6_routing_srh); dissector_add_uint("ipv6.routing.type", IPv6_RT_HEADER_SEGMENT_ROUTING, h); h = create_dissector_handle(dissect_routing6_crh, proto_ipv6_routing_crh); dissector_add_uint("ipv6.routing.type", IPv6_RT_HEADER_COMPACT_16, h); dissector_add_uint("ipv6.routing.type", IPv6_RT_HEADER_COMPACT_32, h); exported_pdu_tap = find_tap_id("IP"); } /* * Editor modelines * * Local Variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * ex: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */