2 * Wireshark's XMPP dissector.
4 * Copyright 2011, Mariusz Okroj <okrojmariusz[]gmail.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/strutil.h>
17 #include <epan/exceptions.h>
19 #include "packet-xmpp.h"
20 #include "packet-xmpp-core.h"
21 #include "packet-xmpp-utils.h"
24 xmpp_copy_hash_table_func(void *key
, void *value
, void *user_data
)
26 GHashTable
*dst
= (GHashTable
*)user_data
;
27 g_hash_table_insert(dst
, key
, value
);
30 static void xmpp_copy_hash_table(GHashTable
*src
, GHashTable
*dst
)
32 g_hash_table_foreach(src
, xmpp_copy_hash_table_func
, dst
);
35 static GList
* xmpp_find_element_by_name(xmpp_element_t
*packet
,const char *name
);
36 static char* xmpp_ep_string_upcase(wmem_allocator_t
*pool
, const char* string
);
37 static void xmpp_unknown_attrs(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo _U_
, xmpp_element_t
*element
, bool displ_short_list
);
41 xmpp_iq_reqresp_track(packet_info
*pinfo
, xmpp_element_t
*packet
, xmpp_conv_info_t
*xmpp_info
)
43 xmpp_transaction_t
*xmpp_trans
= NULL
;
48 attr_id
= xmpp_get_attr(packet
, "id");
54 id
= wmem_strdup(pinfo
->pool
, attr_id
->value
);
56 if (!pinfo
->fd
->visited
) {
57 xmpp_trans
= (xmpp_transaction_t
*)wmem_tree_lookup_string(xmpp_info
->req_resp
, id
, WMEM_TREE_STRING_NOCASE
);
59 xmpp_trans
->resp_frame
= pinfo
->num
;
62 char *se_id
= wmem_strdup(wmem_file_scope(), id
);
64 xmpp_trans
= wmem_new(wmem_file_scope(), xmpp_transaction_t
);
65 xmpp_trans
->req_frame
= pinfo
->num
;
66 xmpp_trans
->resp_frame
= 0;
68 wmem_tree_insert_string(xmpp_info
->req_resp
, se_id
, (void *) xmpp_trans
, WMEM_TREE_STRING_NOCASE
);
73 wmem_tree_lookup_string(xmpp_info
->req_resp
, id
, WMEM_TREE_STRING_NOCASE
);
78 xmpp_jingle_session_track(packet_info
*pinfo
, xmpp_element_t
*packet
, xmpp_conv_info_t
*xmpp_info
)
80 xmpp_element_t
*jingle_packet
;
81 GList
*jingle_packet_l
;
83 jingle_packet_l
= xmpp_find_element_by_name(packet
,"jingle");
84 jingle_packet
= (xmpp_element_t
*)(jingle_packet_l
?jingle_packet_l
->data
:NULL
);
86 if (jingle_packet
&& !pinfo
->fd
->visited
) {
88 xmpp_attr_t
*attr_sid
;
94 attr_id
= xmpp_get_attr(packet
, "id");
99 attr_sid
= xmpp_get_attr(jingle_packet
, "sid");
104 se_id
= wmem_strdup(wmem_file_scope(), attr_id
->value
);
105 se_sid
= wmem_strdup(wmem_file_scope(), attr_sid
->value
);
107 wmem_tree_insert_string(xmpp_info
->jingle_sessions
, se_id
, (void*) se_sid
, WMEM_TREE_STRING_NOCASE
);
112 xmpp_gtalk_session_track(packet_info
*pinfo
, xmpp_element_t
*packet
, xmpp_conv_info_t
*xmpp_info
)
114 xmpp_element_t
*gtalk_packet
;
115 GList
*gtalk_packet_l
;
117 gtalk_packet_l
= xmpp_find_element_by_name(packet
,"session");
118 gtalk_packet
= (xmpp_element_t
*)(gtalk_packet_l
?gtalk_packet_l
->data
:NULL
);
121 if (gtalk_packet
&& !pinfo
->fd
->visited
) {
122 xmpp_attr_t
*attr_id
;
123 xmpp_attr_t
*attr_sid
;
128 xmpp_attr_t
*xmlns
= xmpp_get_attr(gtalk_packet
, "xmlns");
129 if(xmlns
&& strcmp(xmlns
->value
,"http://www.google.com/session") != 0)
132 attr_id
= xmpp_get_attr(packet
, "id");
137 attr_sid
= xmpp_get_attr(gtalk_packet
, "id");
142 se_id
= wmem_strdup(wmem_file_scope(), attr_id
->value
);
143 se_sid
= wmem_strdup(wmem_file_scope(), attr_sid
->value
);
145 wmem_tree_insert_string(xmpp_info
->gtalk_sessions
, se_id
, (void*) se_sid
, WMEM_TREE_STRING_NOCASE
);
150 xmpp_ibb_session_track(packet_info
*pinfo
, xmpp_element_t
*packet
, xmpp_conv_info_t
*xmpp_info
)
152 xmpp_element_t
*ibb_packet
= NULL
;
155 if(strcmp(packet
->name
, "message") == 0)
157 ibb_packet_l
= xmpp_find_element_by_name(packet
,"data");
158 ibb_packet
= (xmpp_element_t
*)(ibb_packet_l
?ibb_packet_l
->data
:NULL
);
160 } else if(strcmp(packet
->name
, "iq") == 0)
162 ibb_packet_l
= xmpp_find_element_by_name(packet
,"open");
165 ibb_packet_l
= xmpp_find_element_by_name(packet
,"close");
167 ibb_packet_l
= xmpp_find_element_by_name(packet
,"data");
169 ibb_packet
= (xmpp_element_t
*)(ibb_packet_l
?ibb_packet_l
->data
:NULL
);
172 if (ibb_packet
&& !pinfo
->fd
->visited
) {
173 xmpp_attr_t
*attr_id
;
174 xmpp_attr_t
*attr_sid
;
180 attr_id
= xmpp_get_attr(packet
, "id");
181 attr_sid
= xmpp_get_attr(ibb_packet
, "sid");
182 if(attr_id
&& attr_sid
)
184 se_id
= wmem_strdup(wmem_file_scope(), attr_id
->value
);
185 se_sid
= wmem_strdup(wmem_file_scope(), attr_sid
->value
);
186 wmem_tree_insert_string(xmpp_info
->ibb_sessions
, se_id
, (void*) se_sid
, WMEM_TREE_STRING_NOCASE
);
192 // NOLINTNEXTLINE(misc-no-recursion)
193 xmpp_unknown_items(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, xmpp_element_t
*element
, unsigned level
)
195 GList
*childs
= element
->elements
;
197 DISSECTOR_ASSERT( level
< ETT_UNKNOWN_LEN
);
199 xmpp_unknown_attrs(tree
, tvb
, pinfo
, element
, true);
203 proto_tree_add_string(tree
, hf_xmpp_cdata
, tvb
, element
->data
->offset
, element
->data
->length
, element
->data
->value
);
208 xmpp_element_t
*child
= (xmpp_element_t
*)childs
->data
;
209 proto_item
*child_item
;
210 proto_tree
*child_tree
= proto_tree_add_subtree(tree
, tvb
, child
->offset
, child
->length
,
211 ett_unknown
[level
], &child_item
, xmpp_ep_string_upcase(pinfo
->pool
, child
->name
));
213 if(child
->default_ns_abbrev
)
214 proto_item_append_text(child_item
, "(%s)", child
->default_ns_abbrev
);
216 xmpp_unknown_items(child_tree
, tvb
, pinfo
, child
, level
+1);
218 childs
= childs
->next
;
223 xmpp_unknown(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, xmpp_element_t
*element
)
225 GList
*childs
= element
->elements
;
227 /*element has unrecognized elements*/
230 xmpp_element_t
*child
= (xmpp_element_t
*)childs
->data
;
233 proto_item
*unknown_item
;
234 proto_tree
*unknown_tree
;
236 unknown_item
= proto_tree_add_string_format(tree
,
237 hf_xmpp_unknown
, tvb
, child
->offset
, child
->length
, child
->name
,
238 "%s", xmpp_ep_string_upcase(pinfo
->pool
, child
->name
));
240 unknown_tree
= proto_item_add_subtree(unknown_item
, ett_unknown
[0]);
242 /*Add COL_INFO only if root element is IQ*/
243 if(strcmp(element
->name
,"iq")==0)
244 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", xmpp_ep_string_upcase(pinfo
->pool
, child
->name
));
246 if(child
->default_ns_abbrev
)
247 proto_item_append_text(unknown_item
,"(%s)",child
->default_ns_abbrev
);
249 xmpp_unknown_items(unknown_tree
, tvb
, pinfo
, child
, 1);
250 proto_item_append_text(unknown_item
, " [UNKNOWN]");
251 expert_add_info_format(pinfo
, unknown_item
, &ei_xmpp_unknown_element
, "Unknown element: %s", child
->name
);
253 childs
= childs
->next
;
258 cleanup_glist_cb(void *user_data
) {
259 GList
*li
= (GList
*)user_data
;
265 xmpp_unknown_attrs(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo _U_
, xmpp_element_t
*element
, bool displ_short_list
)
267 proto_item
*item
= proto_tree_get_parent(tree
);
269 GList
*keys
= g_hash_table_get_keys(element
->attrs
);
270 GList
*values
= g_hash_table_get_values(element
->attrs
);
272 GList
*keys_head
= keys
, *values_head
= values
;
274 CLEANUP_PUSH_PFX(k
, cleanup_glist_cb
, keys_head
);
275 CLEANUP_PUSH_PFX(v
, cleanup_glist_cb
, values_head
);
277 bool short_list_started
= false;
279 while(keys
&& values
)
281 xmpp_attr_t
*attr
= (xmpp_attr_t
*) values
->data
;
282 if (!attr
->was_read
) {
283 if (displ_short_list
) {
284 if (!short_list_started
)
285 proto_item_append_text(item
, " [");
287 proto_item_append_text(item
, " ");
288 proto_item_append_text(item
, "%s=\"%s\"", (char*) keys
->data
, attr
->value
);
290 short_list_started
= true;
293 /*If unknown element has xmlns attrib then header field hf_xmpp_xmlns is added to the tree.
294 In other case only text.*/
295 if (strcmp((const char *)keys
->data
, "xmlns") == 0)
296 proto_tree_add_string(tree
, hf_xmpp_xmlns
, tvb
, attr
->offset
, attr
->length
, attr
->value
);
298 /*xmlns may looks like xmlns:abbrev="sth"*/
299 const char *xmlns_needle
= ws_ascii_strcasestr((const char *)keys
->data
, "xmlns:");
300 if (xmlns_needle
&& xmlns_needle
== keys
->data
) {
301 proto_tree_add_string_format(tree
, hf_xmpp_xmlns
, tvb
, attr
->offset
, attr
->length
, attr
->value
,"%s: %s", (char*)keys
->data
, attr
->value
);
303 proto_item
* unknown_attr_item
;
304 unknown_attr_item
= proto_tree_add_string_format(tree
,
305 hf_xmpp_unknown_attr
, tvb
, attr
->offset
, attr
->length
,
306 attr
->name
, "%s: %s", attr
->name
, attr
->value
);
307 proto_item_append_text(unknown_attr_item
, " [UNKNOWN ATTR]");
308 expert_add_info_format(pinfo
, unknown_attr_item
, &ei_xmpp_unknown_attribute
, "Unknown attribute %s", attr
->name
);
313 values
= values
->next
;
316 if(short_list_started
&& displ_short_list
)
317 proto_item_append_text(item
, "]");
319 CLEANUP_CALL_AND_POP_PFX(v
);
320 CLEANUP_CALL_AND_POP_PFX(k
);
324 xmpp_cdata(proto_tree
*tree
, tvbuff_t
*tvb
, xmpp_element_t
*element
, int hf
)
329 proto_tree_add_string(tree
, hf_xmpp_cdata
, tvb
, element
->data
->offset
, element
->data
->length
, element
->data
->value
);
331 proto_tree_add_string(tree
, hf
, tvb
, element
->data
->offset
, element
->data
->length
, element
->data
->value
);
336 proto_tree_add_string_format_value(tree
, hf_xmpp_cdata
, tvb
, 0, 0, "", "(empty)");
338 proto_tree_add_string(tree
, hf
, tvb
, 0, 0, "");
343 /* displays element that looks like <element_name>element_value</element_name>
344 * ELEMENT_NAME: element_value as TEXT in PROTO_TREE
347 xmpp_simple_cdata_elem(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo _U_
, xmpp_element_t
*element
)
349 proto_tree_add_string_format(tree
, hf_xmpp_cdata
, tvb
, element
->offset
, element
->length
, xmpp_elem_cdata(element
),
350 "%s: %s", xmpp_ep_string_upcase(pinfo
->pool
, element
->name
), xmpp_elem_cdata(element
));
354 xmpp_ep_init_array_t(wmem_allocator_t
*pool
, const char** array
, int len
)
356 xmpp_array_t
*result
;
358 result
= wmem_new(pool
, xmpp_array_t
);
359 result
->data
= (void *) array
;
360 result
->length
= len
;
366 xmpp_ep_init_attr_t(wmem_allocator_t
*pool
, const char *value
, int offset
, int length
)
369 result
= wmem_new(pool
, xmpp_attr_t
);
370 result
->value
= value
;
371 result
->offset
= offset
;
372 result
->length
= length
;
379 xmpp_ep_string_upcase(wmem_allocator_t
*pool
, const char* string
)
381 int len
= (int)strlen(string
);
383 char* result
= (char *)wmem_alloc0(pool
, len
+1);
386 result
[i
] = string
[i
];
388 if(string
[i
]>='a' && string
[i
]<='z')
396 xmpp_element_t_cmp(const void *a
, const void *b
)
398 int result
= strcmp(((const xmpp_element_t
*)a
)->name
,((const xmpp_element_t
*)b
)->name
);
400 if(result
== 0 && ((const xmpp_element_t
*)a
)->was_read
)
407 xmpp_find_element_by_name(xmpp_element_t
*packet
,const char *name
)
409 GList
*found_elements
;
410 xmpp_element_t
*search_element
;
412 /*create fake element only with name*/
413 search_element
= wmem_new(wmem_packet_scope(), xmpp_element_t
);
414 search_element
->name
= wmem_strdup(wmem_packet_scope(), name
);
416 found_elements
= g_list_find_custom(packet
->elements
, search_element
, xmpp_element_t_cmp
);
419 return found_elements
;
426 * function searches element in packet and sets it as read.
427 * if element doesn't exist, NULL is returned.
428 * If element is set as read, it is invisible for these functions.*/
430 xmpp_steal_element_by_name(xmpp_element_t
*packet
,const char *name
)
433 xmpp_element_t
*element
= NULL
;
435 element_l
= xmpp_find_element_by_name(packet
, name
);
439 element
= (xmpp_element_t
*)element_l
->data
;
440 element
->was_read
= true;
448 xmpp_steal_element_by_names(xmpp_element_t
*packet
, const char **names
, int names_len
)
451 xmpp_element_t
*el
= NULL
;
453 for(i
= 0; i
<names_len
; i
++)
455 if((el
= xmpp_steal_element_by_name(packet
, names
[i
])))
463 xmpp_steal_element_by_attr(xmpp_element_t
*packet
, const char *attr_name
, const char *attr_value
)
465 GList
*childs
= packet
->elements
;
466 xmpp_element_t
*result
= NULL
;
469 xmpp_element_t
*child_elem
= (xmpp_element_t
*)childs
->data
;
470 xmpp_attr_t
*attr
= xmpp_get_attr(child_elem
, attr_name
);
473 attr
->was_read
= false;
475 if (!child_elem
->was_read
&& attr
&& strcmp(attr
->value
, attr_value
) == 0) {
477 result
= (xmpp_element_t
*)childs
->data
;
479 result
->was_read
= true;
483 childs
= childs
->next
;
490 xmpp_steal_element_by_name_and_attr(xmpp_element_t
*packet
, const char *name
, const char *attr_name
, const char *attr_value
)
492 GList
*childs
= packet
->elements
;
493 xmpp_element_t
*result
= NULL
;
496 xmpp_element_t
*child_elem
= (xmpp_element_t
*)childs
->data
;
497 xmpp_attr_t
*attr
= xmpp_get_attr(child_elem
, attr_name
);
500 attr
->was_read
= false;
502 if (!child_elem
->was_read
&& attr
&& strcmp(child_elem
->name
, name
) == 0 && strcmp(attr
->value
, attr_value
) == 0) {
504 result
= (xmpp_element_t
*)childs
->data
;
506 result
->was_read
= true;
510 childs
= childs
->next
;
516 xmpp_get_first_element(xmpp_element_t
*packet
)
518 if(packet
->elements
&& packet
->elements
->data
)
519 return (xmpp_element_t
*)packet
->elements
->data
;
525 xmpp_element_t_cleanup(void* userdata
)
527 xmpp_element_t
*node
= (xmpp_element_t
*)userdata
;
529 xmpp_element_t_tree_free(node
);
533 Function converts xml_frame_t structure to xmpp_element_t (simpler representation)
536 // NOLINTNEXTLINE(misc-no-recursion)
537 xmpp_xml_frame_to_element_t(packet_info
*pinfo
, xml_frame_t
*xml_frame
, xmpp_element_t
*parent
, tvbuff_t
*tvb
)
540 xmpp_element_t
*node
= wmem_new0(pinfo
->pool
, xmpp_element_t
);
543 tvbparse_elem_t
* elem
;
545 node
->attrs
= g_hash_table_new(g_str_hash
, g_str_equal
);
546 node
->elements
= NULL
;
548 node
->was_read
= false;
549 node
->default_ns_abbrev
= NULL
;
551 node
->name
= wmem_strdup(pinfo
->pool
, xml_frame
->name_orig_case
);
555 node
->namespaces
= g_hash_table_new(g_str_hash
, g_str_equal
);
558 xmpp_copy_hash_table(parent
->namespaces
, node
->namespaces
);
561 g_hash_table_insert(node
->namespaces
, (void *)"", (void *)"jabber:client");
564 node
->offset
= xml_frame
->start_offset
;
565 node
->length
= xml_frame
->length
;
567 /* We might throw an exception recursively creating child nodes.
568 * Make sure we free the GHashTables created above (and the GList
569 * or child nodes already added) if that happens.
571 CLEANUP_PUSH(xmpp_element_t_cleanup
, node
);
573 tt
= tvbparse_init(pinfo
->pool
, tvb
,node
->offset
,-1,NULL
,want_ignore
);
575 if((elem
= tvbparse_get(tt
,want_stream_end_with_ns
))!=NULL
)
577 node
->default_ns_abbrev
= tvb_get_string_enc(pinfo
->pool
, elem
->sub
->tvb
, elem
->sub
->offset
, elem
->sub
->len
, ENC_ASCII
);
580 child
= xml_frame
->first_child
;
584 if(child
->type
!= XML_FRAME_TAG
)
586 if(child
->type
== XML_FRAME_ATTRIB
)
590 const char *xmlns_needle
= NULL
;
592 xmpp_attr_t
*attr
= wmem_new(pinfo
->pool
, xmpp_attr_t
);
595 attr
->was_read
= false;
597 if (child
->value
!= NULL
) {
598 l
= tvb_reported_length(child
->value
);
599 value
= (char *)wmem_alloc0(pinfo
->pool
, l
+ 1);
600 tvb_memcpy(child
->value
, value
, 0, l
);
603 attr
->offset
= child
->start_offset
;
604 attr
->length
= child
->length
;
606 attr
->name
= wmem_strdup(pinfo
->pool
, child
->name_orig_case
);
608 g_hash_table_insert(node
->attrs
,(void *)attr
->name
,(void *)attr
);
610 /*checking that attr->name looks like xmlns:ns*/
611 xmlns_needle
= ws_ascii_strcasestr(attr
->name
, "xmlns");
613 if(xmlns_needle
== attr
->name
)
615 if(attr
->name
[5] == ':' && strlen(attr
->name
) > 6)
617 g_hash_table_insert(node
->namespaces
, (void *)wmem_strdup(pinfo
->pool
, &attr
->name
[6]), (void *)wmem_strdup(pinfo
->pool
, attr
->value
));
618 } else if(attr
->name
[5] == '\0')
620 g_hash_table_insert(node
->namespaces
, (void *)"", (void *)wmem_strdup(pinfo
->pool
, attr
->value
));
626 else if( child
->type
== XML_FRAME_CDATA
)
628 xmpp_data_t
*data
= NULL
;
632 data
= wmem_new(pinfo
->pool
, xmpp_data_t
);
636 if (child
->value
!= NULL
) {
637 l
= tvb_reported_length(child
->value
);
638 value
= (char *)wmem_alloc0(pinfo
->pool
, l
+ 1);
639 tvb_memcpy(child
->value
, value
, 0, l
);
644 data
->offset
= child
->start_offset
;
645 data
->length
= child
->length
;
650 increment_dissection_depth(pinfo
);
651 node
->elements
= g_list_append(node
->elements
,(void *)xmpp_xml_frame_to_element_t(pinfo
, child
, node
,tvb
));
652 decrement_dissection_depth(pinfo
);
655 child
= child
->next_sibling
;
664 // NOLINTNEXTLINE(misc-no-recursion)
665 xmpp_element_t_tree_free(xmpp_element_t
*root
)
667 GList
*childs
= root
->elements
;
669 g_hash_table_destroy(root
->attrs
);
670 g_hash_table_destroy(root
->namespaces
);
674 xmpp_element_t
*child
= (xmpp_element_t
*)childs
->data
;
676 // Our depth should be limited by the check in xmpp_xml_frame_to_element_t
677 xmpp_element_t_tree_free(child
);
678 childs
= childs
->next
;
680 g_list_free(root
->elements
);
683 /*Function recognize attribute names if they looks like xmlns:ns*/
685 attr_find_pred(void *key
, void *value _U_
, void *user_data
)
687 char *attr_name
= (char*) user_data
;
689 if( strcmp(attr_name
, "xmlns") == 0 )
691 const char *first_occur
= ws_ascii_strcasestr((const char *)key
, "xmlns:");
692 if(first_occur
&& first_occur
== key
)
700 /*Functions returns element's attribute by name and set as read*/
702 xmpp_get_attr(xmpp_element_t
*element
, const char* attr_name
)
704 xmpp_attr_t
*result
= (xmpp_attr_t
*)g_hash_table_lookup(element
->attrs
, attr_name
);
708 result
= (xmpp_attr_t
*)g_hash_table_find(element
->attrs
, attr_find_pred
, (void *)attr_name
);
712 result
->was_read
= true;
717 /*Functions returns element's attribute by name and namespace abbrev*/
719 xmpp_get_attr_ext(packet_info
*pinfo
, xmpp_element_t
*element
, const char* attr_name
, const char* ns_abbrev
)
724 if(strcmp(ns_abbrev
,"")==0)
725 search_phrase
= wmem_strdup(pinfo
->pool
, attr_name
);
726 else if(strcmp(attr_name
, "xmlns") == 0)
727 search_phrase
= wmem_strdup_printf(pinfo
->pool
, "%s:%s",attr_name
, ns_abbrev
);
729 search_phrase
= wmem_strdup_printf(pinfo
->pool
, "%s:%s", ns_abbrev
, attr_name
);
731 result
= (xmpp_attr_t
*)g_hash_table_lookup(element
->attrs
, search_phrase
);
735 result
= (xmpp_attr_t
*)g_hash_table_find(element
->attrs
, attr_find_pred
, (void *)attr_name
);
739 result
->was_read
= true;
747 xmpp_element_to_string(wmem_allocator_t
*pool
, tvbuff_t
*tvb
, xmpp_element_t
*element
)
751 if(tvb_offset_exists(tvb
, element
->offset
+element
->length
-1))
753 buff
= tvb_get_string_enc(pool
, tvb
, element
->offset
, element
->length
, ENC_ASCII
);
759 children_foreach_hide_func(proto_node
*node
, void *data
)
761 int *i
= (int *)data
;
763 proto_item_set_hidden(node
);
768 children_foreach_show_func(proto_node
*node
, void *data
)
770 int *i
= (int *)data
;
772 proto_item_set_visible(node
);
777 xmpp_proto_tree_hide_first_child(proto_tree
*tree
)
780 proto_tree_children_foreach(tree
, children_foreach_hide_func
, &i
);
784 xmpp_proto_tree_show_first_child(proto_tree
*tree
)
787 proto_tree_children_foreach(tree
, children_foreach_show_func
, &i
);
791 proto_item_get_text(wmem_allocator_t
*pool
, proto_item
*item
)
793 field_info
*fi
= NULL
;
799 fi
= PITEM_FINFO(item
);
808 result
= wmem_strdup(pool
, fi
->rep
->representation
);
814 xmpp_display_attrs(proto_tree
*tree
, xmpp_element_t
*element
, packet_info
*pinfo
, tvbuff_t
*tvb
, const xmpp_attr_info
*attrs
, unsigned n
)
816 proto_item
*item
= proto_tree_get_parent(tree
);
819 bool short_list_started
= false;
821 if(element
->default_ns_abbrev
)
822 proto_item_append_text(item
, "(%s)",element
->default_ns_abbrev
);
824 proto_item_append_text(item
," [");
825 for(i
= 0; i
< n
&& attrs
!=NULL
; i
++)
827 attr
= xmpp_get_attr(element
, attrs
[i
].name
);
830 if(attrs
[i
].phf
!= NULL
)
833 proto_tree_add_string_format(tree
, *attrs
[i
].phf
, tvb
, attr
->offset
, attr
->length
, attr
->value
,"%s: %s", attr
->name
, attr
->value
);
835 proto_tree_add_string(tree
, *attrs
[i
].phf
, tvb
, attr
->offset
, attr
->length
, attr
->value
);
839 proto_tree_add_string_format(tree
, hf_xmpp_attribute
, tvb
, attr
->offset
, attr
->length
, attr
->value
,
840 "%s: %s", attr
->name
?attr
->name
:attrs
[i
].name
, attr
->value
);
843 if(attrs
[i
].in_short_list
)
845 if(short_list_started
)
847 proto_item_append_text(item
," ");
849 proto_item_append_text(item
,"%s=\"%s\"",attr
->name
?attr
->name
:attrs
[i
].name
, attr
->value
);
850 short_list_started
= true;
853 } else if(attrs
[i
].is_required
)
855 expert_add_info_format(pinfo
, item
, &ei_xmpp_required_attribute
, "Required attribute \"%s\" doesn't appear in \"%s\".", attrs
[i
].name
, element
->name
);
858 if(attrs
[i
].val_func
)
861 attrs
[i
].val_func(pinfo
, item
, attrs
[i
].name
, attr
->value
, attrs
[i
].data
);
863 attrs
[i
].val_func(pinfo
, item
, attrs
[i
].name
, NULL
, attrs
[i
].data
);
866 proto_item_append_text(item
,"]");
868 /*displays attributes that weren't recognized*/
869 xmpp_unknown_attrs(tree
, tvb
, pinfo
, element
, false);
873 xmpp_display_attrs_ext(proto_tree
*tree
, xmpp_element_t
*element
, packet_info
*pinfo
, tvbuff_t
*tvb
, const xmpp_attr_info_ext
*attrs
, unsigned n
)
875 proto_item
*item
= proto_tree_get_parent(tree
);
878 bool short_list_started
= false;
880 GList
*ns_abbrevs_head
, *ns_abbrevs
= g_hash_table_get_keys(element
->namespaces
);
881 GList
*ns_fullnames_head
, *ns_fullnames
= g_hash_table_get_values(element
->namespaces
);
882 ns_abbrevs_head
= ns_abbrevs
;
883 ns_fullnames_head
= ns_fullnames
;
885 if(element
->default_ns_abbrev
)
886 proto_item_append_text(item
, "(%s)",element
->default_ns_abbrev
);
888 proto_item_append_text(item
," [");
889 while(ns_abbrevs
&& ns_fullnames
)
891 for (i
= 0; i
< n
&& attrs
!= NULL
; i
++) {
892 if(strcmp((const char *)(ns_fullnames
->data
), attrs
[i
].ns
) == 0)
894 attr
= xmpp_get_attr_ext(pinfo
, element
, attrs
[i
].info
.name
, (const char *)(ns_abbrevs
->data
));
895 if(!attr
&& element
->default_ns_abbrev
&& strcmp((const char *)ns_abbrevs
->data
, element
->default_ns_abbrev
)==0)
896 attr
= xmpp_get_attr_ext(pinfo
, element
, attrs
[i
].info
.name
, "");
899 if (attrs
[i
].info
.phf
!= NULL
) {
901 proto_tree_add_string_format(tree
, *attrs
[i
].info
.phf
, tvb
, attr
->offset
, attr
->length
, attr
->value
, "%s: %s", attr
->name
, attr
->value
);
903 proto_tree_add_string(tree
, *attrs
[i
].info
.phf
, tvb
, attr
->offset
, attr
->length
, attr
->value
);
905 proto_tree_add_string_format(tree
, hf_xmpp_attribute
, tvb
, attr
->offset
, attr
->length
, attr
->value
,
906 "%s: %s", attr
->name
? attr
->name
: attrs
[i
].info
.name
, attr
->value
);
909 if (attrs
[i
].info
.in_short_list
) {
910 if (short_list_started
) {
911 proto_item_append_text(item
, " ");
913 proto_item_append_text(item
, "%s=\"%s\"", attr
->name
? attr
->name
: attrs
[i
].info
.name
, attr
->value
);
914 short_list_started
= true;
917 } else if (attrs
[i
].info
.is_required
) {
918 expert_add_info_format(pinfo
, item
, &ei_xmpp_required_attribute
, "Required attribute \"%s\" doesn't appear in \"%s\".", attrs
[i
].info
.name
, element
->name
);
921 if (attrs
[i
].info
.val_func
) {
923 attrs
[i
].info
.val_func(pinfo
, item
, attrs
[i
].info
.name
, attr
->value
, attrs
[i
].info
.data
);
925 attrs
[i
].info
.val_func(pinfo
, item
, attrs
[i
].info
.name
, NULL
, attrs
[i
].info
.data
);
929 ns_abbrevs
= ns_abbrevs
->next
;
930 ns_fullnames
= ns_fullnames
->next
;
932 proto_item_append_text(item
,"]");
934 /*displays attributes that weren't recognized*/
935 xmpp_unknown_attrs(tree
, tvb
, pinfo
, element
, false);
937 g_list_free(ns_abbrevs_head
);
938 g_list_free(ns_fullnames_head
);
941 typedef struct _name_attr_t
944 const char *attr_name
;
945 const char *attr_value
;
949 returns pointer to the struct that contains 3 strings(element name, attribute name, attribute value)
952 xmpp_name_attr_struct(wmem_allocator_t
*pool
, const char *name
, const char *attr_name
, const char *attr_value
)
956 result
= wmem_new(pool
, name_attr_t
);
958 result
->attr_name
= attr_name
;
959 result
->attr_value
= attr_value
;
964 xmpp_display_elems(proto_tree
*tree
, xmpp_element_t
*parent
, packet_info
*pinfo
, tvbuff_t
*tvb
, xmpp_elem_info
*elems
, unsigned n
)
968 for(i
= 0; i
< n
&& elems
!=NULL
; i
++)
970 xmpp_element_t
*elem
= NULL
;
972 if(elems
[i
].type
== NAME_AND_ATTR
)
976 const name_attr_t
*a
= (const name_attr_t
*)(elems
[i
].data
);
978 while(loop
&& (elem
= xmpp_steal_element_by_name_and_attr(parent
, a
->name
, a
->attr_name
, a
->attr_value
))!=NULL
)
980 elems
[i
].elem_func(tree
, tvb
, pinfo
, elem
);
981 if(elems
[i
].occurrence
== ONE
)
984 } else if(elems
[i
].type
== NAME
)
987 const char *name
= (const char *)(elems
[i
].data
);
989 while(loop
&& (elem
= xmpp_steal_element_by_name(parent
, name
))!=NULL
)
991 elems
[i
].elem_func(tree
, tvb
, pinfo
, elem
);
992 if(elems
[i
].occurrence
== ONE
)
996 else if(elems
[i
].type
== ATTR
)
999 const name_attr_t
*attr
= (const name_attr_t
*)(elems
[i
].data
);
1001 while(loop
&& (elem
= xmpp_steal_element_by_attr(parent
, attr
->attr_name
, attr
->attr_value
))!=NULL
)
1003 elems
[i
].elem_func(tree
, tvb
, pinfo
, elem
);
1004 if(elems
[i
].occurrence
== ONE
)
1008 } else if(elems
[i
].type
== NAMES
)
1011 const xmpp_array_t
*names
= (const xmpp_array_t
*)(elems
[i
].data
);
1013 while(loop
&& (elem
= xmpp_steal_element_by_names(parent
, (const char**)names
->data
, names
->length
))!=NULL
)
1015 elems
[i
].elem_func(tree
, tvb
, pinfo
, elem
);
1016 if(elems
[i
].occurrence
== ONE
)
1022 xmpp_unknown(tree
, tvb
, pinfo
, parent
);
1026 function checks that variable value is in array ((xmpp_array_t)data)->data
1029 xmpp_val_enum_list(packet_info
*pinfo
, proto_item
*item
, const char *name
, const char *value
, const void *data
)
1031 const xmpp_array_t
*enums_array
= (const xmpp_array_t
*)data
;
1034 bool value_in_enums
= false;
1036 char **enums
= (char**)enums_array
->data
;
1038 if (value
!= NULL
) {
1039 for (i
= 0; i
< enums_array
->length
; i
++) {
1040 if (strcmp(value
, enums
[i
]) == 0) {
1041 value_in_enums
= true;
1045 if (!value_in_enums
) {
1046 expert_add_info_format(pinfo
, item
, &ei_xmpp_field_unexpected_value
, "Field \"%s\" has unexpected value \"%s\"", name
, value
);
1053 xmpp_change_elem_to_attrib(wmem_allocator_t
*pool
, const char *elem_name
, const char *attr_name
, xmpp_element_t
*parent
, xmpp_attr_t
* (*transform_func
)(wmem_allocator_t
*pool
, xmpp_element_t
*element
))
1055 xmpp_element_t
*element
= NULL
;
1056 xmpp_attr_t
*fake_attr
= NULL
;
1058 element
= xmpp_steal_element_by_name(parent
, elem_name
);
1060 fake_attr
= transform_func(pool
, element
);
1063 g_hash_table_insert(parent
->attrs
, (void *)attr_name
, fake_attr
);
1067 xmpp_transform_func_cdata(wmem_allocator_t
*pool
, xmpp_element_t
*elem
)
1069 xmpp_attr_t
*result
= xmpp_ep_init_attr_t(pool
, elem
->data
?elem
->data
->value
:"", elem
->offset
, elem
->length
);
1075 printf_hash_table_func(void *key
, void *value
, void *user_data _U_
)
1077 printf("'%s' '%s'\n", (char*)key
, (char*)value
);
1081 printf_elements(xmpp_element_t
*root
)
1083 GList
*elems
= root
->elements
;
1085 printf("%s\n", root
->name
);
1086 g_hash_table_foreach(root
->namespaces
, printf_hash_table_func
, NULL
);
1089 printf_elements(elems
->data
);
1090 elems
= elems
->next
;
1096 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1101 * indent-tabs-mode: nil
1104 * ex: set shiftwidth=4 tabstop=8 expandtab:
1105 * :indentSize=4:tabSize=8:noTabs=true: