From 99d3112464295290efc854f7b17c628fddb7e2fd Mon Sep 17 00:00:00 2001 From: David Perry Date: Tue, 15 Nov 2022 16:38:30 +0000 Subject: [PATCH] Show the address space of IPv6 addresses --- epan/dissectors/packet-ipv6.c | 141 ++++++++++++++++++++++++++++++++-- 1 file changed, 133 insertions(+), 8 deletions(-) diff --git a/epan/dissectors/packet-ipv6.c b/epan/dissectors/packet-ipv6.c index 7be3e5675d..81c11417a2 100644 --- a/epan/dissectors/packet-ipv6.c +++ b/epan/dissectors/packet-ipv6.c @@ -160,6 +160,7 @@ 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_host = -1; static int hf_ipv6_src_slaac_mac = -1; static int hf_ipv6_src_isatap_ipv4 = -1; @@ -170,6 +171,7 @@ 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_host = -1; static int hf_ipv6_dst_slaac_mac = -1; static int hf_ipv6_dst_isatap_ipv4 = -1; @@ -180,6 +182,7 @@ 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_host = -1; static int hf_ipv6_slaac_mac = -1; static int hf_ipv6_isatap_ipv4 = -1; @@ -359,6 +362,23 @@ 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_host; +}; + +static struct ipv6_addr_info_s ipv6_src_info = { + &hf_ipv6_src, + &hf_ipv6_src_addr_space, + &hf_ipv6_src_host, +}; +static struct ipv6_addr_info_s ipv6_dst_info = { + &hf_ipv6_dst, + &hf_ipv6_dst_addr_space, + &hf_ipv6_dst_host, +}; + static int hf_geoip_country = -1; static int hf_geoip_country_iso = -1; static int hf_geoip_city = -1; @@ -384,6 +404,7 @@ 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_traffic_class = -1; static gint ett_ipv6_opt = -1; static gint ett_ipv6_opt_type = -1; @@ -405,6 +426,8 @@ 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; @@ -701,6 +724,9 @@ 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; @@ -2777,22 +2803,93 @@ ipv6_get_jumbo_plen(tvbuff_t *tvb, gint offset) return 0; } +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 */ + const guint8 unspecified[IPv6_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + const guint8 loopback[IPv6_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + + vtree = proto_item_add_subtree(vis, ett_ipv6_detail); + itree = proto_item_add_subtree(invis, ett_ipv6_detail); + + if (tvb_memeql(tvb, offset, unspecified, IPv6_ADDR_SIZE) == 0) { + /* RFC 4291 section 2.4: unspecified address */ + ti = proto_tree_add_string(vtree, *addr_info->hf_addr_space, tvb, offset, IPv6_ADDR_SIZE, "Unspecified"); + proto_item_set_generated(ti); + if (addr_info == &ipv6_dst_info) { + /* "Shouldn't" see this one as a destination */ + expert_add_info(pinfo, ti, &ei_ipv6_dst_addr_not_unspecified); + } + + ti = proto_tree_add_string(itree, hf_ipv6_addr_space, tvb, offset, IPv6_ADDR_SIZE, "Unspecified"); + proto_item_set_generated(ti); + } + else if (tvb_memeql(tvb, offset, loopback, IPv6_ADDR_SIZE) == 0) { + /* RFC 4291 section 2.4: loopback address */ + ti = proto_tree_add_string(vtree, *addr_info->hf_addr_space, tvb, offset, IPv6_ADDR_SIZE, "Loopback"); + proto_item_set_generated(ti); + ti = proto_tree_add_string(itree, hf_ipv6_addr_space, tvb, offset, IPv6_ADDR_SIZE, "Loopback"); + proto_item_set_generated(ti); + } + else 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); + } + else if ((tvb_get_ntohs(tvb, offset) & 0xFFC0) == 0xFE80) { + /* RFC 4291 section 2.4: Link-local unicast */ + 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) { + /* RFC 4291 section 2.4: Global unicast */ + 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 { + /* Technically anything else is also global unicast, but... */ + 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); + } +} + static void add_ipv6_address(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset, - gint hf_addr, gint hf_host) + struct ipv6_addr_info_s *addr_info) { address addr; const char *name; - proto_item *ti; + proto_item *ti, *vis, *invis; - proto_tree_add_item(tree, hf_addr, tvb, offset, IPv6_ADDR_SIZE, ENC_NA); - ti = proto_tree_add_item(tree, hf_ipv6_addr, tvb, offset, IPv6_ADDR_SIZE, ENC_NA); - proto_item_set_hidden(ti); + 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); - ti = proto_tree_add_string(tree, hf_host, tvb, offset, IPv6_ADDR_SIZE, name); + 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); @@ -3129,13 +3226,13 @@ dissect_ipv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_ ip6_hlim = tvb_get_guint8(tvb, offset + IP6H_CTL_HLIM); /* Source address */ - add_ipv6_address(pinfo, ipv6_tree, tvb, offset + IP6H_SRC, hf_ipv6_src, hf_ipv6_src_host); + 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, hf_ipv6_dst, hf_ipv6_dst_host); + 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); @@ -3347,6 +3444,11 @@ proto_register_ipv6(void) 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_host, { "Source Host", "ipv6.src_host", FT_STRING, BASE_NONE, NULL, 0x0, @@ -3397,6 +3499,11 @@ proto_register_ipv6(void) 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_host, { "Destination Host", "ipv6.dst_host", FT_STRING, BASE_NONE, NULL, 0x0, @@ -3447,6 +3554,11 @@ proto_register_ipv6(void) 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_host, { "Source or Destination Host", "ipv6.host", FT_STRING, BASE_NONE, NULL, 0x0, @@ -4456,6 +4568,7 @@ proto_register_ipv6(void) static gint *ett_ipv6[] = { &ett_ipv6_proto, + &ett_ipv6_detail, &ett_ipv6_traffic_class, &ett_geoip_info, &ett_ipv6_opt, @@ -4554,6 +4667,10 @@ proto_register_ipv6(void) { &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 } } }; @@ -4565,6 +4682,10 @@ proto_register_ipv6(void) }; 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 } @@ -4684,6 +4805,10 @@ proto_register_ipv6(void) "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",