From 5823e6e50bad432ff7b6ea6c3c0dc2dc9232b469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Valverde?= Date: Mon, 5 Oct 2015 13:51:58 +0100 Subject: [PATCH] Remove duplicate transport ports from proto tree summary Don't display duplicate ports if transport name resolution is not enabled (for UDP/TCP/DCCP). Also introduce col_append_port() to handle info column port display with name resolution in a uniform format. Change-Id: Icb8ac45f726b7c539b4534c62061473e9b582753 Reviewed-on: https://code.wireshark.org/review/10804 Petri-Dish: Michael Mann Tested-by: Petri Dish Buildbot Reviewed-by: Michael Mann --- epan/addr_resolv.c | 147 ++++++++++++++++------------------ epan/addr_resolv.h | 22 ++++- epan/column-utils.c | 17 +++- epan/column-utils.h | 14 +++- epan/dissectors/packet-dccp.c | 30 +++---- epan/dissectors/packet-tcp.c | 39 ++++----- epan/dissectors/packet-udp.c | 27 +++---- wsutil/utf8_entities.h | 1 + 8 files changed, 154 insertions(+), 143 deletions(-) diff --git a/epan/addr_resolv.c b/epan/addr_resolv.c index 8aab2bdc9c..fb36e88117 100644 --- a/epan/addr_resolv.c +++ b/epan/addr_resolv.c @@ -167,14 +167,6 @@ typedef struct { } subnet_length_entry_t; -#if 0 -typedef struct serv_port { - gchar *udp_name; - gchar *tcp_name; - gchar *sctp_name; - gchar *dccp_name; -} serv_port_t; -#endif /* hash table used for IPX network lookup */ /* XXX - check goodness of hash function */ @@ -620,77 +612,63 @@ wmem_utoa(wmem_allocator_t *allocator, guint port) return bp; } - static const gchar * -serv_name_lookup(const guint port, const port_type proto) +_serv_name_lookup(port_type proto, guint port, serv_port_t **value_ret) { serv_port_t *serv_port_table; - gchar *name; serv_port_table = (serv_port_t *)g_hash_table_lookup(serv_port_hashtable, &port); - if (serv_port_table) { - /* Set which table we should look up port in */ - switch(proto) { - case PT_UDP: - if (serv_port_table->udp_name) { - return serv_port_table->udp_name; - } - break; - case PT_TCP: - if (serv_port_table->tcp_name) { - return serv_port_table->tcp_name; - } - break; - case PT_SCTP: - if (serv_port_table->sctp_name) { - return serv_port_table->sctp_name; - } - break; - case PT_DCCP: - if (serv_port_table->dccp_name) { - return serv_port_table->dccp_name; - } - break; - default: - /* not yet implemented */ - return NULL; - /*NOTREACHED*/ - } /* proto */ - } + if (value_ret != NULL) + *value_ret = serv_port_table; - /* Use numerical port string */ - name = (gchar*)g_malloc(16); - guint32_to_str_buf(port, name, 16); + if (serv_port_table == NULL) + return NULL; + + switch (proto) { + case PT_UDP: + return serv_port_table->udp_name; + case PT_TCP: + return serv_port_table->tcp_name; + case PT_SCTP: + return serv_port_table->sctp_name; + case PT_DCCP: + return serv_port_table->dccp_name; + default: + break; + } + return NULL; +} + +const gchar * +try_serv_name_lookup(port_type proto, guint port) +{ + return _serv_name_lookup(proto, port, NULL); +} + +const gchar * +serv_name_lookup(port_type proto, guint port) +{ + serv_port_t *serv_port_table = NULL; + const char *name; + guint *key; + + name = _serv_name_lookup(proto, port, &serv_port_table); + if (name != NULL) + return name; if (serv_port_table == NULL) { - int *key; - - key = (int *)g_new(int, 1); + key = (guint *)g_new(guint, 1); *key = port; - serv_port_table = g_new0(serv_port_t,1); + serv_port_table = g_new0(serv_port_t, 1); g_hash_table_insert(serv_port_hashtable, key, serv_port_table); } - switch(proto) { - case PT_UDP: - serv_port_table->udp_name = name; - break; - case PT_TCP: - serv_port_table->tcp_name = name; - break; - case PT_SCTP: - serv_port_table->sctp_name = name; - break; - case PT_DCCP: - serv_port_table->dccp_name = name; - break; - default: - return NULL; - /*NOTREACHED*/ + if (serv_port_table->numeric == NULL) { + serv_port_table->numeric = g_strdup_printf("%u", port); } - return name; -} /* serv_name_lookup */ + return serv_port_table->numeric; +} static void destroy_serv_port(gpointer data) @@ -700,6 +678,7 @@ destroy_serv_port(gpointer data) g_free(table->tcp_name); g_free(table->sctp_name); g_free(table->dccp_name); + g_free(table->numeric); g_free(table); } @@ -2958,7 +2937,7 @@ udp_port_to_display(wmem_allocator_t *allocator, guint port) return wmem_utoa(allocator, port); } - return wmem_strdup(allocator, serv_name_lookup(port, PT_UDP)); + return wmem_strdup(allocator, serv_name_lookup(PT_UDP, port)); } /* udp_port_to_display */ @@ -2970,7 +2949,7 @@ dccp_port_to_display(wmem_allocator_t *allocator, guint port) return wmem_utoa(allocator, port); } - return wmem_strdup(allocator, serv_name_lookup(port, PT_DCCP)); + return wmem_strdup(allocator, serv_name_lookup(PT_DCCP, port)); } /* dccp_port_to_display */ @@ -2982,7 +2961,7 @@ tcp_port_to_display(wmem_allocator_t *allocator, guint port) return wmem_utoa(allocator, port); } - return wmem_strdup(allocator, serv_name_lookup(port, PT_TCP)); + return wmem_strdup(allocator, serv_name_lookup(PT_TCP, port)); } /* tcp_port_to_display */ @@ -2994,22 +2973,36 @@ sctp_port_to_display(wmem_allocator_t *allocator, guint port) return wmem_utoa(allocator, port); } - return wmem_strdup(allocator, serv_name_lookup(port, PT_SCTP)); + return wmem_strdup(allocator, serv_name_lookup(PT_SCTP, port)); } /* sctp_port_to_display */ -int -port_with_resolution_to_str_buf(gchar *buf, gulong buf_size, port_type port_typ, guint16 port_num) +gchar * +port_with_resolution_to_str(wmem_allocator_t *scope, port_type proto, guint port) { - const gchar *port_res_str; + const gchar *port_str; - if (!gbl_resolv_flags.transport_name || - (port_typ == PT_NONE) || - ((port_res_str = serv_name_lookup(port_num, port_typ)) == NULL)) { + if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) { /* No name resolution support, just return port string */ - return g_snprintf(buf, buf_size, "%u", port_num); + return wmem_strdup_printf(scope, "%u", port); } - return g_snprintf(buf, buf_size, "%s (%u)", port_res_str, port_num); + port_str = serv_name_lookup(proto, port); + g_assert(port_str); + return wmem_strdup_printf(scope, "%s (%u)", port_str, port); +} + +int +port_with_resolution_to_str_buf(gchar *buf, gulong buf_size, port_type proto, guint port) +{ + const gchar *port_str; + + if (!gbl_resolv_flags.transport_name || (proto == PT_NONE)) { + /* No name resolution support, just return port string */ + return g_snprintf(buf, buf_size, "%u", port); + } + port_str = serv_name_lookup(proto, port); + g_assert(port_str); + return g_snprintf(buf, buf_size, "%s (%u)", port_str, port); } gchar * diff --git a/epan/addr_resolv.h b/epan/addr_resolv.h index 13e48df667..9645fe0c47 100644 --- a/epan/addr_resolv.h +++ b/epan/addr_resolv.h @@ -77,6 +77,7 @@ typedef struct serv_port { gchar *tcp_name; gchar *sctp_name; gchar *dccp_name; + gchar *numeric; } serv_port_t; /* @@ -140,12 +141,31 @@ extern gchar *dccp_port_to_display(wmem_allocator_t *allocator, guint port); */ WS_DLL_PUBLIC gchar *sctp_port_to_display(wmem_allocator_t *allocator, guint port); +/* + * serv_name_lookup() returns the well known service name string, or numeric + * representation if one doesn't exist. + */ +WS_DLL_PUBLIC const gchar *serv_name_lookup(port_type proto, guint port); + +/* + * try_serv_name_lookup() returns the well known service name string, or NULL if + * one doesn't exist. + */ +WS_DLL_PUBLIC const gchar *try_serv_name_lookup(port_type proto, guint port); + +/* + * port_with_resolution_to_str() prints the " ()" port + * string. + */ +WS_DLL_PUBLIC gchar *port_with_resolution_to_str(wmem_allocator_t *scope, + port_type proto, guint port); + /* * port_with_resolution_to_str_buf() prints the " ()" port * string to 'buf'. Return value is the same as g_snprintf(). */ WS_DLL_PUBLIC int port_with_resolution_to_str_buf(gchar *buf, gulong buf_size, - port_type port_typ, guint16 port_num); + port_type proto, guint port); /* * Asynchronous host name lookup initialization, processing, and cleanup diff --git a/epan/column-utils.c b/epan/column-utils.c index 8db8521e67..b52e08ff8f 100644 --- a/epan/column-utils.c +++ b/epan/column-utils.c @@ -410,7 +410,7 @@ col_append_lstr(column_info *cinfo, const gint el, const gchar *str1, ...) } void -col_append_str_uint(column_info *cinfo, const gint col, const gchar *sep, const gchar *abbrev, guint32 val) +col_append_str_uint(column_info *cinfo, const gint col, const gchar *abbrev, guint32 val, const gchar *sep) { char buf[16]; @@ -418,6 +418,21 @@ col_append_str_uint(column_info *cinfo, const gint col, const gchar *sep, const col_append_lstr(cinfo, col, sep ? sep : "", abbrev, "=", buf, COL_ADD_LSTR_TERMINATOR); } +void +col_append_port(column_info *cinfo, const gint col, port_type typ, guint16 val, const gchar *sep) +{ + const char *str; + char buf[32]; + + if (gbl_resolv_flags.transport_name && + (str = try_serv_name_lookup(typ, val)) != NULL) { + g_snprintf(buf, sizeof(buf), "%s(%u)", str, val); + } else { + g_snprintf(buf, sizeof(buf), "%u", val); + } + col_append_lstr(cinfo, col, sep ? sep : "", buf, COL_ADD_LSTR_TERMINATOR); +} + static void col_do_append_fstr(column_info *cinfo, const int el, const char *separator, const char *format, va_list ap) { diff --git a/epan/column-utils.h b/epan/column-utils.h index af4eb28c48..d89a745678 100644 --- a/epan/column-utils.h +++ b/epan/column-utils.h @@ -273,11 +273,21 @@ WS_DLL_PUBLIC void col_append_str(column_info *cinfo, const gint col, const gcha * * @param cinfo the current packet row * @param col the column to use, e.g. COL_INFO - * @param sep an optional separator to prepend to abbrev * @param abbrev the string to append * @param val the value to append + * @param sep an optional separator to _prepend_ to abbrev */ -WS_DLL_PUBLIC void col_append_str_uint(column_info *cinfo, const gint col, const gchar *sep, const gchar *abbrev, guint32 val); +WS_DLL_PUBLIC void col_append_str_uint(column_info *cinfo, const gint col, const gchar *abbrev, guint32 val, const gchar *sep); + +/** Append a transport port to a column element, the text will be copied. + * + * @param cinfo the current packet row + * @param col the column to use, e.g. COL_INFO + * @param typ the port type to resolve + * @param val the port value to append + * @param sep an optional separator to _prepend_ to the port string + */ +WS_DLL_PUBLIC void col_append_port(column_info *cinfo, const gint col, port_type typ, guint16 val, const gchar *sep); /* Append the given strings (terminated by COL_ADD_LSTR_TERMINATOR) to a column element, * diff --git a/epan/dissectors/packet-dccp.c b/epan/dissectors/packet-dccp.c index 661cd202e3..308ecab0d0 100644 --- a/epan/dissectors/packet-dccp.c +++ b/epan/dissectors/packet-dccp.c @@ -598,7 +598,6 @@ dissect_dccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ proto_tree *dccp_options_tree = NULL; proto_item *dccp_item = NULL; proto_item *hidden_item, *offset_item; - vec_t cksum_vec[4]; guint32 phdr[2]; guint16 computed_cksum; @@ -609,35 +608,24 @@ dissect_dccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_ guint advertised_dccp_header_len = 0; guint options_len = 0; e_dccphdr *dccph; - gchar *src_port_str, *dst_port_str; dccph = wmem_new0(wmem_packet_scope(), e_dccphdr); - - SET_ADDRESS(&dccph->ip_src, pinfo->src.type, pinfo->src.len, - pinfo->src.data); - SET_ADDRESS(&dccph->ip_dst, pinfo->dst.type, pinfo->dst.len, - pinfo->dst.data); + dccph->sport = tvb_get_ntohs(tvb, offset); + dccph->dport = tvb_get_ntohs(tvb, offset + 2); + COPY_ADDRESS_SHALLOW(&dccph->ip_src, &pinfo->src); + COPY_ADDRESS_SHALLOW(&dccph->ip_dst, &pinfo->dst); col_set_str(pinfo->cinfo, COL_PROTOCOL, "DCCP"); col_clear(pinfo->cinfo, COL_INFO); - /* Extract generic header */ - dccph->sport = tvb_get_ntohs(tvb, offset); - dccph->dport = tvb_get_ntohs(tvb, offset + 2); - - src_port_str = dccp_port_to_display(wmem_packet_scope(), dccph->sport); - dst_port_str = dccp_port_to_display(wmem_packet_scope(), dccph->dport); - col_add_lstr(pinfo->cinfo, COL_INFO, - src_port_str, - " "UTF8_RIGHTWARDS_ARROW" ", - dst_port_str, - COL_ADD_LSTR_TERMINATOR); + col_append_port(pinfo->cinfo, COL_INFO, PT_DCCP, dccph->sport, NULL); + col_append_port(pinfo->cinfo, COL_INFO, PT_DCCP, dccph->dport, UTF8_LONG_RIGHTWARDS_ARROW); dccp_item = proto_tree_add_item(tree, proto_dccp, tvb, offset, -1, ENC_NA); if (dccp_summary_in_tree) { - proto_item_append_text(dccp_item, ", Src Port: %s (%u), Dst Port: %s (%u)", - src_port_str, dccph->sport, - dst_port_str, dccph->dport); + proto_item_append_text(dccp_item, ", Src Port: %s, Dst Port: %s", + port_with_resolution_to_str(wmem_packet_scope(), PT_DCCP, dccph->sport), + port_with_resolution_to_str(wmem_packet_scope(), PT_DCCP, dccph->dport)); } dccp_tree = proto_item_add_subtree(dccp_item, ett_dccp); diff --git a/epan/dissectors/packet-tcp.c b/epan/dissectors/packet-tcp.c index 36c82b701a..0adb5c7451 100644 --- a/epan/dissectors/packet-tcp.c +++ b/epan/dissectors/packet-tcp.c @@ -2513,7 +2513,7 @@ static void tcp_info_append_uint(packet_info *pinfo, const char *abbrev, guint32 val) { /* fstr(" %s=%u", abbrev, val) */ - col_append_str_uint(pinfo->cinfo, COL_INFO, " ", abbrev, val); + col_append_str_uint(pinfo->cinfo, COL_INFO, abbrev, val, " "); } static void @@ -4353,37 +4353,25 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) struct tcp_per_packet_data_t *tcppd=NULL; proto_item *item; proto_tree *checksum_tree; - gchar *src_port_str, *dst_port_str; - tcph=wmem_new(wmem_packet_scope(), struct tcpheader); + tcph = wmem_new0(wmem_packet_scope(), struct tcpheader); + tcph->th_sport = tvb_get_ntohs(tvb, offset); + tcph->th_dport = tvb_get_ntohs(tvb, offset + 2); COPY_ADDRESS_SHALLOW(&tcph->ip_src, &pinfo->src); COPY_ADDRESS_SHALLOW(&tcph->ip_dst, &pinfo->dst); col_set_str(pinfo->cinfo, COL_PROTOCOL, "TCP"); - - /* Clear out the Info column. */ col_clear(pinfo->cinfo, COL_INFO); - tcph->th_sport = tvb_get_ntohs(tvb, offset); - tcph->th_dport = tvb_get_ntohs(tvb, offset + 2); - - src_port_str = tcp_port_to_display(wmem_packet_scope(), tcph->th_sport); - dst_port_str = tcp_port_to_display(wmem_packet_scope(), tcph->th_dport); - col_add_lstr(pinfo->cinfo, COL_INFO, - src_port_str, - " "UTF8_RIGHTWARDS_ARROW" ", - dst_port_str, - COL_ADD_LSTR_TERMINATOR); + col_append_port(pinfo->cinfo, COL_INFO, PT_TCP, tcph->th_sport, NULL); + col_append_port(pinfo->cinfo, COL_INFO, PT_TCP, tcph->th_dport, UTF8_LONG_RIGHTWARDS_ARROW); if (tree) { + ti = proto_tree_add_item(tree, proto_tcp, tvb, 0, -1, ENC_NA); if (tcp_summary_in_tree) { - ti = proto_tree_add_protocol_format(tree, proto_tcp, tvb, 0, -1, - "Transmission Control Protocol, Src Port: %s (%u), Dst Port: %s (%u)", - src_port_str, tcph->th_sport, - dst_port_str, tcph->th_dport); - } - else { - ti = proto_tree_add_item(tree, proto_tcp, tvb, 0, -1, ENC_NA); + proto_item_append_text(ti, ", Src Port: %s, Dst Port: %s", + port_with_resolution_to_str(wmem_packet_scope(), PT_TCP, tcph->th_sport), + port_with_resolution_to_str(wmem_packet_scope(), PT_TCP, tcph->th_dport)); } tcp_tree = proto_item_add_subtree(ti, ett_tcp); p_add_proto_data(pinfo->pool, pinfo, proto_tcp, pinfo->curr_layer_num, tcp_tree); @@ -4677,13 +4665,14 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) if(tcph->th_flags & TH_SYN) { if(tcph->th_flags & TH_ACK) { - expert_add_info_format(pinfo, tf_syn, &ei_tcp_connection_sack, "Connection establish acknowledge (SYN+ACK): server port %s", src_port_str); + expert_add_info_format(pinfo, tf_syn, &ei_tcp_connection_sack, + "Connection establish acknowledge (SYN+ACK): server port %u", tcph->th_sport); /* Save the server port to help determine dissector used */ tcpd->server_port = tcph->th_sport; } else { - expert_add_info_format(pinfo, tf_syn, &ei_tcp_connection_syn, "Connection establish request (SYN): server port %s", - dst_port_str); + expert_add_info_format(pinfo, tf_syn, &ei_tcp_connection_syn, + "Connection establish request (SYN): server port %u", tcph->th_dport); /* Save the server port to help determine dissector used */ tcpd->server_port = tcph->th_dport; tcpd->ts_mru_syn.secs = pinfo->fd->abs_ts.secs; diff --git a/epan/dissectors/packet-udp.c b/epan/dissectors/packet-udp.c index 4bbde774b8..2592a570a3 100644 --- a/epan/dissectors/packet-udp.c +++ b/epan/dissectors/packet-udp.c @@ -688,35 +688,28 @@ dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ip_proto) conversation_t *conv = NULL; struct udp_analysis *udpd = NULL; proto_tree *process_tree; - gchar *src_port_str, *dst_port_str; gboolean udp_jumbogram = FALSE; - udph = wmem_new(wmem_packet_scope(), e_udphdr); + udph = wmem_new0(wmem_packet_scope(), e_udphdr); udph->uh_sport = tvb_get_ntohs(tvb, offset); udph->uh_dport = tvb_get_ntohs(tvb, offset + 2); - udph->uh_ulen = udph->uh_sum_cov = tvb_get_ntohs(tvb, offset + 4); - udph->uh_sum = tvb_get_ntohs(tvb, offset + 6); - SET_ADDRESS(&udph->ip_src, pinfo->src.type, pinfo->src.len, pinfo->src.data); - SET_ADDRESS(&udph->ip_dst, pinfo->dst.type, pinfo->dst.len, pinfo->dst.data); + COPY_ADDRESS_SHALLOW(&udph->ip_src, &pinfo->src); + COPY_ADDRESS_SHALLOW(&udph->ip_dst, &pinfo->dst); col_set_str(pinfo->cinfo, COL_PROTOCOL, (ip_proto == IP_PROTO_UDP) ? "UDP" : "UDP-Lite"); col_clear(pinfo->cinfo, COL_INFO); - src_port_str = udp_port_to_display(wmem_packet_scope(), udph->uh_sport); - dst_port_str = udp_port_to_display(wmem_packet_scope(), udph->uh_dport); - col_add_lstr(pinfo->cinfo, COL_INFO, - src_port_str, - " "UTF8_RIGHTWARDS_ARROW" ", - dst_port_str, - COL_ADD_LSTR_TERMINATOR); + col_append_port(pinfo->cinfo, COL_INFO, PT_UDP, udph->uh_sport, NULL); + col_append_port(pinfo->cinfo, COL_INFO, PT_UDP, udph->uh_dport, UTF8_LONG_RIGHTWARDS_ARROW); reported_len = tvb_reported_length(tvb); len = tvb_captured_length(tvb); ti = proto_tree_add_item(tree, (ip_proto == IP_PROTO_UDP) ? hfi_udp : hfi_udplite, tvb, offset, 8, ENC_NA); if (udp_summary_in_tree) { - proto_item_append_text(ti, ", Src Port: %s (%u), Dst Port: %s (%u)", - src_port_str, udph->uh_sport, dst_port_str, udph->uh_dport); + proto_item_append_text(ti, ", Src Port: %s, Dst Port: %s", + port_with_resolution_to_str(wmem_packet_scope(), PT_UDP, udph->uh_sport), + port_with_resolution_to_str(wmem_packet_scope(), PT_UDP, udph->uh_dport)); } udp_tree = proto_item_add_subtree(ti, ett_udp); p_add_proto_data(pinfo->pool, pinfo, hfi_udp->id, pinfo->curr_layer_num, udp_tree); @@ -742,6 +735,7 @@ dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ip_proto) ((udph->uh_dport - 32768 - 666 - 1) % 3) + 1); } + udph->uh_ulen = udph->uh_sum_cov = tvb_get_ntohs(tvb, offset + 4); if (ip_proto == IP_PROTO_UDP) { len_cov_item = proto_tree_add_item(udp_tree, &hfi_udp_length, tvb, offset + 4, 2, ENC_BIG_ENDIAN); if (udph->uh_ulen == 0 && pinfo->src.type == AT_IPv6) { @@ -787,10 +781,11 @@ dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 ip_proto) } } - col_append_str_uint(pinfo->cinfo, COL_INFO, " ", "Len", udph->uh_ulen - 8); /* Payload length */ + col_append_str_uint(pinfo->cinfo, COL_INFO, "Len", udph->uh_ulen - 8, " "); /* Payload length */ if (udp_jumbogram) col_append_str(pinfo->cinfo, COL_INFO, " [Jumbogram]"); + udph->uh_sum = tvb_get_ntohs(tvb, offset + 6); if (udph->uh_sum == 0) { /* No checksum supplied in the packet. */ if ((ip_proto == IP_PROTO_UDP) && (pinfo->src.type == AT_IPv4)) { diff --git a/wsutil/utf8_entities.h b/wsutil/utf8_entities.h index 50132e742e..0fab083674 100644 --- a/wsutil/utf8_entities.h +++ b/wsutil/utf8_entities.h @@ -39,6 +39,7 @@ #define UTF8_LEFTWARDS_ARROW "\xe2\x86\x90" /* 8592 / 0x2190 */ #define UTF8_RIGHTWARDS_ARROW "\xe2\x86\x92" /* 8594 / 0x2192 */ #define UTF8_LEFT_RIGHT_ARROW "\xe2\x86\x94" /* 8596 / 0x2194 */ +#define UTF8_LONG_RIGHTWARDS_ARROW "\xe2\x9f\xb6" /* 10230 / 0x27f6 */ #define UTF8_PLACE_OF_INTEREST_SIGN "\xe2\x8c\x98" /* 8984 / 0x2318 */