2 * Routines for eXtensible Messaging Client Protocol (XMCP) dissection
3 * Copyright 2011, Glenn Matthews <glenn.matthews@cisco.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * Copied from packet-stun.c
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * XMCP is a proprietary Cisco protocol based very loosely on the
27 * Session Traversal Utilities for NAT (STUN) protocol.
28 * This dissector is capable of understanding XMCP versions 1.0 and 2.0.
33 #include <epan/packet.h>
34 #include <epan/ipproto.h>
35 #include <epan/addr_resolv.h>
36 #include <epan/prefs.h>
37 #include <epan/expert.h>
38 #include "packet-tcp.h"
40 void proto_register_xmcp(void);
42 static dissector_table_t media_type_dissector_table;
44 /* Initialize the protocol and registered fields */
45 static int proto_xmcp = -1;
47 static int hf_xmcp_response_in = -1;
48 static int hf_xmcp_response_to = -1;
49 static int hf_xmcp_time = -1;
51 typedef struct _xmcp_transaction_t {
52 guint32 request_frame;
53 guint32 response_frame;
54 nstime_t request_time;
55 gboolean request_is_keepalive;
58 typedef struct _xmcp_conv_info_t {
59 wmem_tree_t *transaction_pdus;
62 static int hf_xmcp_type = -1;
63 static int hf_xmcp_type_reserved = -1;
64 static int hf_xmcp_type_class = -1;
65 static int hf_xmcp_type_method = -1;
66 static int hf_xmcp_length = -1;
67 static int hf_xmcp_cookie = -1;
68 static int hf_xmcp_id = -1;
69 static int hf_xmcp_attributes = -1;
70 static int hf_xmcp_attr = -1;
71 static int hf_xmcp_msg_is_keepalive = -1;
73 static int xmcp_attr_type = -1;
74 static int xmcp_attr_length = -1;
75 static int xmcp_attr_value = -1; /* generic value for unrecognized attrs */
76 static int xmcp_attr_padding = -1; /* generic value for TLV padding bytes */
77 static int xmcp_attr_reserved = -1;
78 static int xmcp_attr_username = -1;
79 static int xmcp_attr_message_integrity = -1;
80 static int xmcp_attr_error_reserved = -1;
81 static int xmcp_attr_error_class = -1;
82 static int xmcp_attr_error_number = -1;
83 static int xmcp_attr_error_code = -1;
84 static int xmcp_attr_error_reason = -1;
85 static int xmcp_attr_realm = -1;
86 static int xmcp_attr_nonce = -1;
87 static int xmcp_attr_client_name = -1;
88 static int xmcp_attr_client_handle = -1;
89 static int xmcp_attr_version_major = -1;
90 static int xmcp_attr_version_minor = -1;
91 static int xmcp_attr_page_size = -1;
92 static int xmcp_attr_client_label = -1;
93 static int xmcp_attr_keepalive = -1;
94 static int xmcp_attr_serv_service = -1;
95 static int xmcp_attr_serv_subservice = -1;
96 static int xmcp_attr_serv_instance = -1;
97 static int xmcp_attr_servtrans_family = -1;
98 static int xmcp_attr_servtrans_port = -1;
99 static int xmcp_attr_servtrans_ipv4 = -1;
100 static int xmcp_attr_servtrans_ipv6 = -1;
101 static int xmcp_attr_service_protocol = -1;
102 static int xmcp_attr_flag = -1;
103 static int xmcp_attr_flag_type = -1;
104 static int xmcp_attr_flag_value = -1;
105 static int xmcp_attr_flag_removal_reason_network_withdraw = -1;
106 static int xmcp_attr_flag_removal_reason_reserved = -1;
107 static int xmcp_attr_flag_trust = -1;
108 static int xmcp_attr_flag_visibility_unauthenticated = -1;
109 static int xmcp_attr_flag_visibility_reserved = -1;
110 static int xmcp_attr_service_version = -1;
111 static int xmcp_attr_service_data = -1;
112 static int xmcp_attr_subscription_id = -1;
113 static int xmcp_attr_service_removed_reason = -1;
114 static int xmcp_attr_domain = -1;
116 static gint ett_xmcp = -1;
117 static gint ett_xmcp_type = -1;
118 static gint ett_xmcp_attr_all = -1;
119 static gint ett_xmcp_attr = -1;
120 static gint ett_xmcp_attr_flag = -1;
122 static expert_field ei_xmcp_message_class_reserved = EI_INIT;
123 static expert_field ei_xmcp_attr_length_bad = EI_INIT;
124 static expert_field ei_xmcp_attr_error_number_out_of_range = EI_INIT;
125 static expert_field ei_xmcp_type_reserved_not_zero = EI_INIT;
126 static expert_field ei_xmcp_data_following_message_integrity = EI_INIT;
127 static expert_field ei_xmcp_msg_type_method_reserved = EI_INIT;
128 static expert_field ei_xmcp_xmcp_attr_servtrans_unknown = EI_INIT;
129 static expert_field ei_xmcp_attr_realm_incorrect = EI_INIT;
130 static expert_field ei_xmcp_new_session = EI_INIT;
131 static expert_field ei_xmcp_response_without_request = EI_INIT;
132 static expert_field ei_xmcp_length_bad = EI_INIT;
133 static expert_field ei_xmcp_error_response = EI_INIT;
134 static expert_field ei_xmcp_magic_cookie_incorrect = EI_INIT;
135 static expert_field ei_xmcp_attr_type_unknown = EI_INIT;
136 static expert_field ei_xmcp_session_termination = EI_INIT;
137 static expert_field ei_xmcp_attr_error_code_unusual = EI_INIT;
139 #define TCP_PORT_XMCP 4788
140 #define XMCP_MAGIC_COOKIE 0x7f5a9bc7
142 void proto_reg_handoff_xmcp(void);
143 static guint global_xmcp_tcp_port = TCP_PORT_XMCP;
145 #define XMCP_HDR_LEN 20
146 #define XMCP_ATTR_HDR_LEN 4
148 #define XMCP_TYPE_RESERVED 0xc000
149 #define XMCP_TYPE_CLASS 0x0110
150 #define XMCP_TYPE_METHOD 0x3eef
152 static const int *xmcp_type_fields[] = {
153 &hf_xmcp_type_reserved,
154 &hf_xmcp_type_method,
159 #define XMCP_CLASS_REQUEST 0x00
160 #define XMCP_CLASS_RESERVED 0x01
161 #define XMCP_CLASS_RESPONSE_SUCCESS 0x10
162 #define XMCP_CLASS_RESPONSE_ERROR 0x11
164 static const value_string classes[] = {
165 {XMCP_CLASS_REQUEST, "Request"},
166 {XMCP_CLASS_RESERVED, "RESERVED-CLASS"},
167 {XMCP_CLASS_RESPONSE_SUCCESS, "Success Response"},
168 {XMCP_CLASS_RESPONSE_ERROR, "Error Response"},
172 #define XMCP_METHOD_ILLEGAL 0x000
173 #define XMCP_METHOD_REGISTER 0x001
174 #define XMCP_METHOD_UNREGISTER 0x002
175 #define XMCP_METHOD_REG_REVOKE 0x003
176 #define XMCP_METHOD_PUBLISH 0x004
177 #define XMCP_METHOD_UNPUBLISH 0x005
178 #define XMCP_METHOD_PUB_REVOKE 0x006
179 #define XMCP_METHOD_SUBSCRIBE 0x007
180 #define XMCP_METHOD_UNSUBSCRIBE 0x008
181 #define XMCP_METHOD_WITHDRAW 0x009
182 #define XMCP_METHOD_NOTIFY 0x00a
183 #define XMCP_METHOD_KEEPALIVE 0x00b
185 static const value_string methods[] = {
186 {XMCP_METHOD_ILLEGAL, "Illegal"},
187 {XMCP_METHOD_REGISTER, "Register"},
188 {XMCP_METHOD_UNREGISTER, "Unregister"},
189 {XMCP_METHOD_REG_REVOKE, "RegisterRevoke"},
190 {XMCP_METHOD_PUBLISH, "Publish"},
191 {XMCP_METHOD_UNPUBLISH, "Unpublish"},
192 {XMCP_METHOD_PUB_REVOKE, "PublishRevoke"},
193 {XMCP_METHOD_SUBSCRIBE, "Subscribe"},
194 {XMCP_METHOD_UNSUBSCRIBE, "Unsubscribe"},
195 {XMCP_METHOD_WITHDRAW, "Withdraw"},
196 {XMCP_METHOD_NOTIFY, "Notify"},
197 {XMCP_METHOD_KEEPALIVE, "Keepalive"},
201 #define XMCP_USERNAME 0x0006
202 #define XMCP_MESSAGE_INTEGRITY 0x0008
203 #define XMCP_ERROR_CODE 0x0009
204 #define XMCP_REALM 0x0014
205 #define XMCP_NONCE 0x0015
206 #define XMCP_CLIENT_NAME 0x1001
207 #define XMCP_CLIENT_HANDLE 0x1002
208 #define XMCP_PROTOCOL_VERSION 0x1003
209 #define XMCP_PAGE_SIZE 0x1004
210 #define XMCP_CLIENT_LABEL 0x1005
211 #define XMCP_KEEPALIVE 0x1006
212 #define XMCP_SERVICE_IDENTITY 0x1007
213 #define XMCP_SERVICE_TRANSPORT 0x1008
214 #define XMCP_SERVICE_PROTOCOL 0x1009
215 #define XMCP_FLAGS 0x100a
216 #define XMCP_SERVICE_VERSION 0x100b
217 #define XMCP_SERVICE_DATA 0x100c
218 #define XMCP_SUBSCRIPTION_ID 0x100e
219 #define XMCP_SERVICE_REMOVED_REASON 0x100f
220 #define XMCP_DOMAIN 0x1011
222 static const value_string attributes[] = {
223 /* Attributes inherited from STUN */
224 {XMCP_USERNAME, "Username"},
225 {XMCP_MESSAGE_INTEGRITY, "Message-Integrity"},
226 {XMCP_ERROR_CODE, "Error-Code"},
227 {XMCP_REALM, "Realm"},
228 {XMCP_NONCE, "Nonce"},
229 /* Attributes specific to XMCP */
230 {XMCP_CLIENT_NAME, "Client-Name"},
231 {XMCP_CLIENT_HANDLE, "Client-Handle"},
232 {XMCP_PROTOCOL_VERSION, "Protocol-Version"},
233 {XMCP_PAGE_SIZE, "PageSize"},
234 {XMCP_CLIENT_LABEL, "ClientLabel"},
235 {XMCP_KEEPALIVE, "Keepalive"},
236 {XMCP_SERVICE_IDENTITY, "ServiceIdentity"},
237 {XMCP_SERVICE_TRANSPORT, "ServiceTransportAddr"},
238 {XMCP_SERVICE_PROTOCOL, "ServiceProtocol"},
239 {XMCP_FLAGS, "Flags"},
240 {XMCP_SERVICE_VERSION, "ServiceVersion"},
241 {XMCP_SERVICE_DATA, "ServiceData"},
242 {XMCP_SUBSCRIPTION_ID, "SubscriptionID"},
243 {XMCP_SERVICE_REMOVED_REASON, "ServiceRemovedReason"},
244 {XMCP_DOMAIN, "Domain"},
248 static const value_string error_codes[] = {
249 {400, "Bad Request"},
250 {401, "Unauthorized"},
251 {413, "Request Too Large"},
252 {431, "Integrity Check Failure"},
253 {435, "Nonce Required"},
254 {436, "Unknown Username"},
255 {438, "Stale Nonce"},
256 {471, "Bad Client Handle"},
257 {472, "Version Number Too Low"},
258 {473, "Unknown Service"},
259 {474, "Unregistered"},
260 {475, "Invalid ServiceIdentity"},
261 {476, "Unknown Subscription"},
262 {477, "Already Registered"},
263 {478, "Unsupported Protocol Version"},
264 {479, "Unknown or Forbidden Domain"},
265 {499, "Miscellaneous Request Error"},
266 {500, "Responder Error"},
267 {501, "Not Implemented"},
271 static const value_string address_families[] = {
277 #define XMCP_FLAG_REMOVAL_REASON 0x0001
278 #define XMCP_FLAG_TRUST 0x0002
279 #define XMCP_FLAG_SERVICE_VISIBILITY 0x0003
281 static const value_string flag_types[] = {
282 {XMCP_FLAG_REMOVAL_REASON, "Removal Reason"},
283 {XMCP_FLAG_TRUST, "Trust"},
284 {XMCP_FLAG_SERVICE_VISIBILITY, "Service Visibility"},
288 /* Values for specific flag types */
289 #define XMCP_REMOVAL_REASON_NETWORK_WITHDRAW 0x0001
290 #define XMCP_REMOVAL_REASON_RESERVED 0xfffe
292 #define XMCP_TRUST_LOCAL 0
293 #define XMCP_TRUST_LEARNED 1
295 static const value_string flag_trust_values[] = {
296 {XMCP_TRUST_LOCAL, "Local"},
297 {XMCP_TRUST_LEARNED, "Learned"},
301 #define XMCP_SERVICE_VISIBILITY_UNAUTHENTICATED 0x0001
302 #define XMCP_SERVICE_VISIBILITY_RESERVED 0xfffe
304 static const value_string service_removed_reasons[] = {
305 {0, "Network withdraw"},
306 {1, "Source withdraw"},
310 /* Dissector state variables */
311 static guint16 xmcp_msg_type_method = XMCP_METHOD_ILLEGAL;
312 static guint16 xmcp_msg_type_class = XMCP_CLASS_RESERVED;
313 static gboolean xmcp_msg_is_keepalive = FALSE;
314 static gint16 xmcp_service_protocol = -1;
315 static gint32 xmcp_service_port = -1;
316 static proto_item *xmcp_it_service_port = NULL;
319 get_xmcp_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
321 return(XMCP_HDR_LEN + tvb_get_ntohs(tvb, offset+2));
325 get_xmcp_attr_padded_len(guint16 attr_length)
328 * As in STUN, all XMCP attributes report their length in bytes,
329 * but are padded to the next 4-byte multiple.
331 return((attr_length + 3) & 0xfffc);
335 get_xmcp_attr_fixed_len(guint16 xmcp_attr)
338 * For fixed-length attributes, return their length.
339 * For variable-length attributes, return 0.
342 case XMCP_CLIENT_HANDLE:
343 case XMCP_PROTOCOL_VERSION:
346 case XMCP_SERVICE_PROTOCOL:
347 case XMCP_SERVICE_VERSION:
348 case XMCP_SUBSCRIPTION_ID:
349 case XMCP_SERVICE_REMOVED_REASON:
352 case XMCP_SERVICE_IDENTITY:
360 get_xmcp_attr_min_len(guint16 xmcp_attr)
365 case XMCP_CLIENT_NAME:
366 case XMCP_CLIENT_LABEL:
368 case XMCP_ERROR_CODE:
370 case XMCP_SERVICE_TRANSPORT:
371 return(8); /* 4-byte fixed plus an IPv4 address */
372 case XMCP_MESSAGE_INTEGRITY:
373 return(20); /* HMAC-SHA1 */
375 return(get_xmcp_attr_fixed_len(xmcp_attr));
380 get_xmcp_attr_max_len(guint16 xmcp_attr) {
384 case XMCP_SERVICE_TRANSPORT:
385 return(20); /* 4-byte fixed plus an IPv6 address */
386 case XMCP_MESSAGE_INTEGRITY:
387 return(32); /* HMAC-SHA-256 */
389 case XMCP_CLIENT_NAME:
390 case XMCP_CLIENT_LABEL:
393 fixed_len = get_xmcp_attr_fixed_len(xmcp_attr);
394 return(fixed_len ? fixed_len : 0xffff);
399 add_xmcp_port_name (void)
401 if (!xmcp_it_service_port || xmcp_service_port == -1)
404 switch(xmcp_service_protocol) {
406 proto_item_append_text(xmcp_it_service_port, " (TCP: %s)",
407 tcp_port_to_display(wmem_packet_scope(), xmcp_service_port));
410 proto_item_append_text(xmcp_it_service_port, " (UDP: %s)",
411 udp_port_to_display(wmem_packet_scope(), xmcp_service_port));
414 proto_item_append_text(xmcp_it_service_port, " (DCCP: %s)",
415 dccp_port_to_display(wmem_packet_scope(), xmcp_service_port));
418 proto_item_append_text(xmcp_it_service_port, " (SCTP: %s)",
419 sctp_port_to_display(wmem_packet_scope(), xmcp_service_port));
427 decode_xmcp_attr_value (proto_tree *attr_tree, guint16 attr_type,
428 guint16 attr_length, tvbuff_t *tvb, guint16 offset,
435 proto_tree_add_item(attr_tree, xmcp_attr_username, tvb, offset,
436 attr_length, ENC_ASCII|ENC_NA);
437 proto_item_append_text(attr_tree, ": %s",
438 tvb_get_string_enc(wmem_packet_scope(), tvb, offset, attr_length, ENC_ASCII));
440 * Many message methods may include this attribute,
441 * but it's only interesting when Registering at first
443 if (xmcp_msg_type_method == XMCP_METHOD_REGISTER) {
444 col_append_fstr(pinfo->cinfo, COL_INFO, ", user \"%s\"",
445 tvb_get_string_enc(wmem_packet_scope(), tvb, offset, attr_length, ENC_ASCII));
448 case XMCP_MESSAGE_INTEGRITY:
449 proto_tree_add_item(attr_tree, xmcp_attr_message_integrity, tvb, offset,
450 attr_length, ENC_NA);
451 /* Message-integrity should be the last attribute in the message */
452 if ((guint)(offset + get_xmcp_attr_padded_len(attr_length)) < tvb_reported_length(tvb)) {
453 expert_add_info(pinfo, attr_tree, &ei_xmcp_data_following_message_integrity);
456 case XMCP_ERROR_CODE:
459 proto_tree_add_item(attr_tree, xmcp_attr_error_reserved, tvb, offset,
461 proto_tree_add_item(attr_tree, xmcp_attr_error_class, tvb, offset,
464 guint8 error_class, error_number;
466 it = proto_tree_add_item(attr_tree, xmcp_attr_error_number, tvb,
467 (offset+3), 1, ENC_BIG_ENDIAN);
469 error_class = tvb_get_guint8(tvb, offset+2) & 0x07;
470 error_number = tvb_get_guint8(tvb, offset+3);
472 if (error_number > 99) {
473 expert_add_info(pinfo, it, &ei_xmcp_attr_error_number_out_of_range);
475 /* Error code = error class + (error num % 100) */
476 error_code = (error_class * 100) + error_number;
477 it = proto_tree_add_uint(attr_tree, xmcp_attr_error_code, tvb,
478 (offset+2), 2, error_code);
479 PROTO_ITEM_SET_GENERATED(it);
480 proto_item_append_text(attr_tree, ": %d", error_code);
481 col_append_fstr(pinfo->cinfo, COL_INFO, ", error %d (%s)", error_code,
482 val_to_str_const(error_code, error_codes, "Unknown"));
485 * All error responses default to a PI_NOTE severity.
486 * Some specific error codes are more significant, so mark them up.
488 switch (error_code) {
489 case 400: /* Bad Request */
490 case 431: /* Integrity Check Failure */
491 case 473: /* Unknown Service */
492 case 476: /* Unknown Subscription */
493 case 477: /* Already Registered */
494 case 499: /* Miscellaneous Request Error */
495 case 500: /* Responder Error */
496 expert_add_info_format(pinfo, it, &ei_xmcp_attr_error_code_unusual, "Unusual error code (%u, %s)", error_code, val_to_str_const(error_code, error_codes, "Unknown"));
505 proto_tree_add_item(attr_tree, xmcp_attr_error_reason, tvb, (offset+4),
506 (attr_length - 4), ENC_ASCII|ENC_NA);
507 proto_item_append_text(attr_tree, " (%s)",
508 tvb_get_string_enc(wmem_packet_scope(), tvb, (offset+4),
509 (attr_length-4), ENC_ASCII));
512 it = proto_tree_add_item(attr_tree, xmcp_attr_realm, tvb, offset,
513 attr_length, ENC_ASCII|ENC_NA);
516 realm = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, attr_length, ENC_ASCII);
517 proto_item_append_text(attr_tree, ": %s", realm);
518 /* In XMCP the REALM string should always be "SAF" including the quotes */
519 if (attr_length != 5 || strncmp(realm, "\"SAF\"", attr_length)) {
520 expert_add_info(pinfo, it, &ei_xmcp_attr_realm_incorrect);
525 proto_tree_add_item(attr_tree, xmcp_attr_nonce, tvb, offset,
526 attr_length, ENC_ASCII|ENC_NA);
527 proto_item_append_text(attr_tree, ": %s",
528 tvb_get_string_enc(wmem_packet_scope(), tvb, offset, attr_length, ENC_ASCII));
530 case XMCP_CLIENT_NAME:
531 proto_tree_add_item(attr_tree, xmcp_attr_client_name, tvb, offset,
532 attr_length, ENC_ASCII|ENC_NA);
533 proto_item_append_text(attr_tree, ": %s",
534 tvb_get_string_enc(wmem_packet_scope(), tvb, offset, attr_length, ENC_ASCII));
535 col_append_fstr(pinfo->cinfo, COL_INFO, ", name \"%s\"",
536 tvb_get_string_enc(wmem_packet_scope(), tvb, offset, attr_length, ENC_ASCII));
538 case XMCP_CLIENT_HANDLE:
541 proto_tree_add_item(attr_tree, xmcp_attr_client_handle, tvb, offset,
543 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
544 col_append_fstr(pinfo->cinfo, COL_INFO, ", handle %u",
545 tvb_get_ntohl(tvb, offset));
547 * A Register request containing a Client-Handle is considered
550 if (xmcp_msg_type_method == XMCP_METHOD_REGISTER &&
551 xmcp_msg_type_class == XMCP_CLASS_REQUEST) {
552 xmcp_msg_is_keepalive = TRUE;
555 case XMCP_PROTOCOL_VERSION:
558 proto_tree_add_item(attr_tree, xmcp_attr_version_major, tvb, offset,
562 proto_tree_add_item(attr_tree, xmcp_attr_version_minor, tvb, (offset+2),
564 proto_item_append_text(attr_tree, ": %u.%u", tvb_get_ntohs(tvb, offset),
565 tvb_get_ntohs(tvb, (offset+2)));
570 proto_tree_add_item(attr_tree, xmcp_attr_page_size, tvb, offset, 4, ENC_BIG_ENDIAN);
571 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
573 case XMCP_CLIENT_LABEL:
574 proto_tree_add_item(attr_tree, xmcp_attr_client_label, tvb, offset,
575 attr_length, ENC_ASCII|ENC_NA);
576 proto_item_append_text(attr_tree, ": %s",
577 tvb_get_string_enc(wmem_packet_scope(), tvb, offset, attr_length, ENC_ASCII));
578 col_append_fstr(pinfo->cinfo, COL_INFO, ", label \"%s\"",
579 tvb_get_string_enc(wmem_packet_scope(), tvb, offset, attr_length, ENC_ASCII));
584 proto_tree_add_item(attr_tree, xmcp_attr_keepalive, tvb, offset, 4, ENC_BIG_ENDIAN);
585 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
587 case XMCP_SERVICE_IDENTITY:
590 proto_tree_add_item(attr_tree, xmcp_attr_serv_service, tvb, offset,
594 proto_tree_add_item(attr_tree, xmcp_attr_serv_subservice, tvb, (offset+2),
596 if (attr_length < 20)
598 proto_tree_add_item(attr_tree, xmcp_attr_serv_instance, tvb, (offset+4),
602 char buf[GUID_STR_LEN];
603 tvb_get_guid(tvb, (offset+4), &guid, ENC_BIG_ENDIAN);
604 guid_to_str_buf(&guid, buf, sizeof(buf));
605 proto_item_append_text(attr_tree, ": %u:%u:%s",
606 tvb_get_ntohs(tvb, offset),
607 tvb_get_ntohs(tvb, (offset+2)), buf);
608 col_append_fstr(pinfo->cinfo, COL_INFO, ", service %u:%u:%s",
609 tvb_get_ntohs(tvb, offset),
610 tvb_get_ntohs(tvb, (offset+2)), buf);
613 case XMCP_SERVICE_TRANSPORT:
615 * One byte of padding, one byte indicating family,
616 * two bytes for port, followed by addr
620 proto_tree_add_item(attr_tree, xmcp_attr_reserved, tvb, offset, 1, ENC_NA);
623 proto_tree_add_item(attr_tree, xmcp_attr_servtrans_family, tvb,
624 (offset+1), 1, ENC_BIG_ENDIAN);
627 xmcp_service_port = tvb_get_ntohs(tvb, (offset+2));
628 xmcp_it_service_port = proto_tree_add_item(attr_tree,
629 xmcp_attr_servtrans_port,
630 tvb, (offset+2), 2, ENC_BIG_ENDIAN);
631 /* If we now know both port and protocol number, fill in the port name */
632 if (xmcp_service_protocol != -1) {
633 add_xmcp_port_name();
635 switch (tvb_get_guint8(tvb, (offset+1))) {
636 case 0x01: /* IPv4 */
637 if (attr_length != 8) {
638 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Malformed IPv4 address");
640 proto_tree_add_item(attr_tree, xmcp_attr_servtrans_ipv4, tvb,
641 (offset+4), 4, ENC_BIG_ENDIAN);
642 proto_item_append_text(attr_tree, ": %s:%u", tvb_ip_to_str(tvb, offset+4),
643 tvb_get_ntohs(tvb, (offset+2)));
646 case 0x02: /* IPv6 */
647 if (attr_length != 20) {
648 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Malformed IPv6 address");
650 proto_tree_add_item(attr_tree, xmcp_attr_servtrans_ipv6, tvb,
651 (offset+4), 16, ENC_NA);
652 proto_item_append_text(attr_tree, ": [%s]:%u", tvb_ip6_to_str(tvb, (offset+4)),
653 tvb_get_ntohs(tvb, (offset+2)));
657 expert_add_info(pinfo, attr_tree, &ei_xmcp_xmcp_attr_servtrans_unknown);
661 case XMCP_SERVICE_PROTOCOL:
662 /* Three bytes of padding followed by a 1-byte protocol number */
665 proto_tree_add_item(attr_tree, xmcp_attr_reserved, tvb, offset, 3, ENC_NA);
666 proto_tree_add_item(attr_tree, xmcp_attr_service_protocol, tvb,
667 (offset+3), 1, ENC_BIG_ENDIAN);
668 xmcp_service_protocol = tvb_get_guint8(tvb, (offset+3));
669 proto_item_append_text(attr_tree, ": %u (%s)", xmcp_service_protocol,
670 val_to_str_ext_const(xmcp_service_protocol,
671 &ipproto_val_ext, "Unknown"));
672 /* If we now know both port and protocol number, fill in the port name */
673 if (xmcp_service_port != -1 && xmcp_it_service_port != NULL) {
674 add_xmcp_port_name();
678 /* Flags is a series of type-value pairs */
679 if (attr_length % 4 != 0) {
680 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Malformed Flags - length not divisible by 4");
683 guint16 flag_type, flag_value, current_offset = offset;
685 proto_tree *flag_tree;
686 while ((current_offset-offset)+3 < attr_length) {
687 flag_type = tvb_get_ntohs(tvb, (current_offset));
688 flag_value = tvb_get_ntohs(tvb, (current_offset+2));
689 ti = proto_tree_add_none_format(attr_tree, xmcp_attr_flag, tvb,
692 val_to_str_const(flag_type, flag_types,
694 flag_tree = proto_item_add_subtree(ti, ett_xmcp_attr_flag);
695 proto_tree_add_item(flag_tree, xmcp_attr_flag_type, tvb,
696 current_offset, 2, ENC_BIG_ENDIAN);
700 case XMCP_FLAG_REMOVAL_REASON:
701 proto_tree_add_item(flag_tree, xmcp_attr_flag_removal_reason_reserved,
702 tvb, current_offset, 2, ENC_BIG_ENDIAN);
703 proto_tree_add_item(flag_tree,
704 xmcp_attr_flag_removal_reason_network_withdraw,
705 tvb, current_offset, 2, ENC_BIG_ENDIAN);
706 if (flag_value & XMCP_REMOVAL_REASON_NETWORK_WITHDRAW) {
707 proto_item_append_text(flag_tree, " (network withdraw)");
710 proto_item_append_text(flag_tree, " (source withdraw)");
713 case XMCP_FLAG_TRUST:
714 proto_tree_add_item(flag_tree, xmcp_attr_flag_trust, tvb,
715 current_offset, 2, ENC_BIG_ENDIAN);
716 proto_item_append_text(flag_tree, " %s",
717 val_to_str_const(flag_value, flag_trust_values,
720 case XMCP_FLAG_SERVICE_VISIBILITY:
721 proto_tree_add_item(flag_tree, xmcp_attr_flag_visibility_reserved,
722 tvb, current_offset, 2, ENC_BIG_ENDIAN);
723 proto_tree_add_item(flag_tree,
724 xmcp_attr_flag_visibility_unauthenticated,
725 tvb, current_offset, 2, ENC_BIG_ENDIAN);
726 if (flag_value & XMCP_SERVICE_VISIBILITY_UNAUTHENTICATED) {
727 proto_item_append_text(flag_tree,
728 " (visible to unauthenticated clients)");
731 proto_item_append_text(flag_tree, " (default)");
735 proto_tree_add_item(flag_tree, xmcp_attr_flag_value, tvb,
736 current_offset, 2, ENC_BIG_ENDIAN);
737 proto_item_append_text(flag_tree, " 0x%04x", flag_value);
744 case XMCP_SERVICE_VERSION:
747 proto_tree_add_item(attr_tree, xmcp_attr_service_version, tvb, offset,
749 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
751 case XMCP_SERVICE_DATA:
752 proto_tree_add_item(attr_tree, xmcp_attr_service_data, tvb, offset,
753 attr_length, ENC_NA);
754 if (attr_length > 0) {
756 guint8 *test_string, *tok;
758 next_tvb = tvb_new_subset_length(tvb, offset, attr_length);
760 * Service-Data is usually (but not always) plain text, specifically XML.
761 * If it "looks like" XML (begins with optional whitespace followed by
763 * Otherwise, try plain-text.
765 test_string = tvb_get_string_enc(wmem_packet_scope(), next_tvb, 0, (attr_length < 32 ?
766 attr_length : 32), ENC_ASCII);
767 tok = strtok(test_string, " \t\r\n");
768 if (tok && tok[0] == '<') {
770 dissector_try_string(media_type_dissector_table, "application/xml",
771 next_tvb, pinfo, attr_tree, NULL);
774 dissector_try_string(media_type_dissector_table, "text/plain",
775 next_tvb, pinfo, attr_tree, NULL);
779 case XMCP_SUBSCRIPTION_ID:
782 proto_tree_add_item(attr_tree, xmcp_attr_subscription_id, tvb, offset,
784 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
785 col_append_fstr(pinfo->cinfo, COL_INFO, ", subscription %u",
786 tvb_get_ntohl(tvb, offset));
788 case XMCP_SERVICE_REMOVED_REASON:
791 proto_tree_add_item(attr_tree, xmcp_attr_service_removed_reason, tvb,
792 offset, 4, ENC_BIG_ENDIAN);
793 proto_item_append_text(attr_tree, ": %s",
794 val_to_str_const(tvb_get_ntohl(tvb, offset),
795 service_removed_reasons,
801 proto_tree_add_item(attr_tree, xmcp_attr_domain, tvb, offset, 4, ENC_BIG_ENDIAN);
802 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
805 proto_tree_add_item(attr_tree, xmcp_attr_value, tvb, offset,
806 attr_length, ENC_NA);
807 expert_add_info(pinfo, attr_tree, &ei_xmcp_attr_type_unknown);
810 if (attr_length % 4 != 0) {
811 proto_tree_add_item(attr_tree, xmcp_attr_padding, tvb, (offset+attr_length),
812 (4 - (attr_length % 4)), ENC_NA);
814 if (attr_length < get_xmcp_attr_min_len(attr_type)) {
815 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Length less than minimum for this attribute type");
816 } else if (attr_length > get_xmcp_attr_max_len(attr_type)) {
817 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Length exceeds maximum for this attribute type");
822 dissect_xmcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
824 guint16 msg_type, msg_length;
825 proto_item *ti = NULL;
826 proto_tree *xmcp_tree, *attr_all_tree, *attr_tree;
827 guint16 offset, attr_type, attr_length;
829 /* For request/response association */
830 guint32 transaction_id[3];
831 wmem_tree_key_t transaction_id_key[2];
832 conversation_t *conversation;
833 xmcp_conv_info_t *xmcp_conv_info;
834 xmcp_transaction_t *xmcp_trans;
836 if (tvb_reported_length(tvb) < XMCP_HDR_LEN) {
839 /* Check for valid message type field */
840 msg_type = tvb_get_ntohs(tvb, 0);
841 if (msg_type & XMCP_TYPE_RESERVED) { /* First 2 bits must be 0 */
844 /* Check for valid "magic cookie" field */
845 if (tvb_get_ntohl(tvb, 4) != XMCP_MAGIC_COOKIE) {
849 col_set_str(pinfo->cinfo, COL_PROTOCOL, "XMCP");
850 /* Clear out stuff in the info column */
851 col_clear(pinfo->cinfo, COL_INFO);
853 /* As in STUN, the first 2 bytes contain the message class and method */
854 xmcp_msg_type_class = ((msg_type & XMCP_TYPE_CLASS) >> 4);
855 xmcp_msg_type_method = (msg_type & XMCP_TYPE_METHOD);
856 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
857 val_to_str_const(xmcp_msg_type_method, methods, "Unknown"),
858 val_to_str_const(xmcp_msg_type_class, classes, "Unknown"));
860 /* Get the transaction ID */
861 transaction_id[0] = tvb_get_ntohl(tvb, 8);
862 transaction_id[1] = tvb_get_ntohl(tvb, 12);
863 transaction_id[2] = tvb_get_ntohl(tvb, 16);
865 transaction_id_key[0].length = 3;
866 transaction_id_key[0].key = transaction_id;
867 transaction_id_key[1].length = 0;
868 transaction_id_key[1].key = NULL;
870 conversation = find_or_create_conversation(pinfo);
872 /* Do we already have XMCP state for this conversation? */
873 xmcp_conv_info = (xmcp_conv_info_t *)conversation_get_proto_data(conversation, proto_xmcp);
874 if (!xmcp_conv_info) {
875 xmcp_conv_info = wmem_new(wmem_file_scope(), xmcp_conv_info_t);
876 xmcp_conv_info->transaction_pdus = wmem_tree_new(wmem_file_scope());
877 conversation_add_proto_data(conversation, proto_xmcp, xmcp_conv_info);
880 /* Find existing transaction entry or create a new one */
881 xmcp_trans = (xmcp_transaction_t *)wmem_tree_lookup32_array(xmcp_conv_info->transaction_pdus,
884 xmcp_trans = wmem_new(wmem_file_scope(), xmcp_transaction_t);
885 xmcp_trans->request_frame = 0;
886 xmcp_trans->response_frame = 0;
887 xmcp_trans->request_time = pinfo->fd->abs_ts;
888 xmcp_trans->request_is_keepalive = FALSE;
889 wmem_tree_insert32_array(xmcp_conv_info->transaction_pdus,
890 transaction_id_key, (void *)xmcp_trans);
893 /* Update transaction entry */
894 if (!pinfo->fd->flags.visited) {
895 if (xmcp_msg_type_class == XMCP_CLASS_REQUEST) {
896 if (xmcp_trans->request_frame == 0) {
897 xmcp_trans->request_frame = pinfo->fd->num;
898 xmcp_trans->request_time = pinfo->fd->abs_ts;
900 } else if (xmcp_msg_type_class != XMCP_CLASS_RESERVED) {
901 if (xmcp_trans->response_frame == 0) {
902 xmcp_trans->response_frame = pinfo->fd->num;
907 ti = proto_tree_add_item(tree, proto_xmcp, tvb, 0, -1, ENC_NA);
908 xmcp_tree = proto_item_add_subtree(ti, ett_xmcp);
910 ti = proto_tree_add_bitmask(xmcp_tree, tvb, 0, hf_xmcp_type, ett_xmcp_type,
911 xmcp_type_fields, ENC_BIG_ENDIAN);
913 if (msg_type & XMCP_TYPE_RESERVED) {
914 expert_add_info(pinfo, ti, &ei_xmcp_type_reserved_not_zero);
916 if (xmcp_msg_type_class == XMCP_CLASS_RESERVED) {
917 expert_add_info(pinfo, ti, &ei_xmcp_message_class_reserved);
918 } else if (xmcp_msg_type_class == XMCP_CLASS_RESPONSE_ERROR) {
919 expert_add_info(pinfo, ti, &ei_xmcp_error_response);
922 if (xmcp_msg_type_method < 0x001 || xmcp_msg_type_method > 0x00b) {
923 expert_add_info(pinfo, ti, &ei_xmcp_msg_type_method_reserved);
927 * Some forms of XMCP overload the Register method for Keepalive packets
928 * rather than using a separate Keepalive method. We'll try to determine from
929 * the message contents whether this message is a Keepalive. Initialize first.
931 xmcp_msg_is_keepalive = (xmcp_trans->request_is_keepalive ||
932 (xmcp_msg_type_method == XMCP_METHOD_KEEPALIVE));
934 /* After the class/method, we have a 2 byte length...*/
935 ti = proto_tree_add_item(xmcp_tree, hf_xmcp_length, tvb, 2, 2, ENC_BIG_ENDIAN);
936 msg_length = tvb_get_ntohs(tvb, 2);
937 if ((guint)(msg_length + XMCP_HDR_LEN) > tvb_reported_length(tvb)) {
938 expert_add_info_format(pinfo, ti, &ei_xmcp_length_bad, "XMCP message length (%u-byte header + %u) exceeds packet length (%u)", XMCP_HDR_LEN, msg_length, tvb_reported_length(tvb));
939 return tvb_length(tvb);
942 /* ...a 4 byte magic cookie... */
943 ti = proto_tree_add_item(xmcp_tree, hf_xmcp_cookie, tvb, 4, 4, ENC_BIG_ENDIAN);
944 if (tvb_get_ntohl(tvb, 4) != XMCP_MAGIC_COOKIE) {
945 expert_add_info(pinfo, ti, &ei_xmcp_magic_cookie_incorrect);
948 /* ...and a 12-byte transaction id */
949 ti = proto_tree_add_item(xmcp_tree, hf_xmcp_id, tvb, 8, 12, ENC_NA);
951 /* Print state tracking in the tree */
952 if (xmcp_msg_type_class == XMCP_CLASS_REQUEST) {
953 if (xmcp_trans->response_frame) {
954 ti = proto_tree_add_uint(xmcp_tree, hf_xmcp_response_in, tvb, 0, 0,
955 xmcp_trans->response_frame);
956 PROTO_ITEM_SET_GENERATED(ti);
958 } else if (xmcp_msg_type_class != XMCP_CLASS_RESERVED) {
959 if (xmcp_trans->request_frame) {
962 ti = proto_tree_add_uint(xmcp_tree, hf_xmcp_response_to, tvb, 0, 0,
963 xmcp_trans->request_frame);
964 PROTO_ITEM_SET_GENERATED(ti);
966 nstime_delta(&ns, &pinfo->fd->abs_ts, &xmcp_trans->request_time);
967 ti = proto_tree_add_time(xmcp_tree, hf_xmcp_time, tvb, 0, 0, &ns);
968 PROTO_ITEM_SET_GENERATED(ti);
970 /* This is a response, but we don't know about a request for this response? */
971 expert_add_info(pinfo, ti, &ei_xmcp_response_without_request);
975 xmcp_service_protocol = -1;
976 xmcp_service_port = -1;
977 xmcp_it_service_port = NULL;
979 /* The header is then followed by "msg_length" bytes of TLV attributes */
980 if (msg_length > 0) {
981 ti = proto_tree_add_item(xmcp_tree, hf_xmcp_attributes, tvb,
982 XMCP_HDR_LEN, msg_length, ENC_NA);
983 attr_all_tree = proto_item_add_subtree(ti, ett_xmcp_attr_all);
985 offset = XMCP_HDR_LEN;
987 while (offset < (msg_length + XMCP_HDR_LEN)) {
988 /* Get type/length of next TLV */
989 attr_type = tvb_get_ntohs(tvb, offset);
990 attr_length = tvb_get_ntohs(tvb, offset+2);
991 ti = proto_tree_add_none_format(attr_all_tree, hf_xmcp_attr, tvb, offset,
993 get_xmcp_attr_padded_len(attr_length)),
995 val_to_str_const(attr_type, attributes,
999 /* Add subtree for this TLV */
1000 attr_tree = proto_item_add_subtree(ti, ett_xmcp_attr);
1002 proto_tree_add_item(attr_tree, xmcp_attr_type, tvb,
1003 offset, 2, ENC_BIG_ENDIAN);
1005 ti = proto_tree_add_item(attr_tree, xmcp_attr_length, tvb,
1006 offset, 2, ENC_BIG_ENDIAN);
1009 if ((offset + attr_length) > (XMCP_HDR_LEN + msg_length)) {
1010 proto_item_append_text(ti, " (bogus, exceeds message length)");
1011 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Attribute length exceeds message length");
1015 decode_xmcp_attr_value(attr_tree, attr_type, attr_length, tvb,
1018 offset += get_xmcp_attr_padded_len(attr_length);
1023 * Flag this message as a keepalive if the attribute analysis
1024 * suggested that it is one
1026 if (xmcp_msg_is_keepalive) {
1027 ti = proto_tree_add_none_format(xmcp_tree, hf_xmcp_msg_is_keepalive, tvb,
1028 0, 0, "This is a Keepalive message");
1029 PROTO_ITEM_SET_GENERATED(ti);
1030 if (xmcp_msg_type_method != XMCP_METHOD_KEEPALIVE) {
1031 col_prepend_fstr(pinfo->cinfo, COL_INFO, "[Keepalive] ");
1033 if (xmcp_msg_type_class == XMCP_CLASS_REQUEST) {
1034 xmcp_trans->request_is_keepalive = TRUE;
1036 } else if (xmcp_msg_type_class == XMCP_CLASS_REQUEST ||
1037 xmcp_msg_type_class == XMCP_CLASS_RESPONSE_SUCCESS) {
1038 if (xmcp_msg_type_method == XMCP_METHOD_REGISTER) {
1039 expert_add_info_format(pinfo, xmcp_tree, &ei_xmcp_new_session, "New session - Register %s", val_to_str_const(xmcp_msg_type_class, classes, ""));
1040 } else if (xmcp_msg_type_method == XMCP_METHOD_UNREGISTER ||
1041 xmcp_msg_type_method == XMCP_METHOD_REG_REVOKE) {
1042 expert_add_info_format(pinfo, xmcp_tree, &ei_xmcp_session_termination, "Session termination - %s %s", val_to_str_const(xmcp_msg_type_method, methods, ""), val_to_str_const(xmcp_msg_type_class, classes, ""));
1046 return tvb_length(tvb);
1050 dissect_xmcp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1052 tcp_dissect_pdus(tvb, pinfo, tree, TRUE, XMCP_HDR_LEN,
1053 get_xmcp_message_len, dissect_xmcp_message, data);
1054 return tvb_length(tvb);
1058 dissect_xmcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1060 /* See if this looks like a real XMCP packet */
1061 if (tvb_length(tvb) < XMCP_HDR_LEN) {
1064 /* Check for valid message type field */
1065 if (tvb_get_ntohs(tvb, 0) & XMCP_TYPE_RESERVED) { /* First 2 bits must be 0 */
1068 /* Check for valid "magic cookie" field */
1069 if (tvb_get_ntohl(tvb, 4) != XMCP_MAGIC_COOKIE) {
1073 /* Good enough to consider a match! */
1074 tcp_dissect_pdus(tvb, pinfo, tree, TRUE, XMCP_HDR_LEN,
1075 get_xmcp_message_len, dissect_xmcp_message, data);
1080 proto_register_xmcp(void)
1082 static hf_register_info hf[] = {
1084 { "Message Type", "xmcp.type",
1085 FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }
1087 { &hf_xmcp_type_reserved,
1088 { "Reserved", "xmcp.type.reserved",
1089 FT_UINT16, BASE_HEX, NULL, XMCP_TYPE_RESERVED, NULL, HFILL }
1091 { &hf_xmcp_type_class,
1092 { "Class", "xmcp.type.class",
1093 FT_UINT16, BASE_HEX, VALS(classes), XMCP_TYPE_CLASS, NULL, HFILL }
1095 { &hf_xmcp_type_method,
1096 { "Method", "xmcp.type.method",
1097 FT_UINT16, BASE_HEX, VALS(methods), XMCP_TYPE_METHOD, NULL, HFILL }
1099 { &hf_xmcp_msg_is_keepalive,
1100 { "Message is Keepalive", "xmcp.analysis.keepalive",
1101 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
1104 { "Message Length", "xmcp.length",
1105 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1108 { "XMCP Magic Cookie", "xmcp.cookie",
1109 FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }
1112 { "Transaction ID", "xmcp.id",
1113 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1115 { &hf_xmcp_response_in,
1116 { "Response In", "xmcp.response-in",
1117 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1118 "The response to this XMCP request is in this frame", HFILL }
1120 { &hf_xmcp_response_to,
1121 { "Response To", "xmcp.response-to",
1122 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1123 "This is a response to the XMCP request in this frame", HFILL }
1126 { "Elapsed Time", "xmcp.time",
1127 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1128 "The time between the Request and the Response", HFILL }
1130 { &hf_xmcp_attributes,
1131 { "Attributes", "xmcp.attributes",
1132 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
1135 { "Attribute", "xmcp.attr",
1136 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
1139 { "Attribute Type", "xmcp.attr.type",
1140 FT_UINT16, BASE_HEX, VALS(attributes), 0x0, NULL, HFILL }
1142 { &xmcp_attr_length,
1143 { "Attribute Length", "xmcp.attr.length",
1144 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1147 { "Attribute Value", "xmcp.attr.value",
1148 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}
1150 { &xmcp_attr_padding,
1151 { "Padding", "xmcp.attr.padding",
1152 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1154 { &xmcp_attr_reserved,
1155 { "Reserved", "xmcp.attr.reserved",
1156 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1158 { &xmcp_attr_username,
1159 { "Username", "xmcp.attr.username",
1160 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1162 { &xmcp_attr_message_integrity,
1163 { "Message-Integrity", "xmcp.attr.hmac",
1164 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1166 { &xmcp_attr_error_reserved,
1167 { "Reserved", "xmcp.attr.error.reserved",
1168 FT_UINT24, BASE_HEX, NULL, 0xFFFFF8, NULL, HFILL }
1170 { &xmcp_attr_error_class,
1171 { "Error Class", "xmcp.attr.error.class",
1172 FT_UINT24, BASE_DEC, NULL, 0x000007, NULL, HFILL}
1174 { &xmcp_attr_error_number,
1175 { "Error Number", "xmcp.attr.error.number",
1176 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
1178 { &xmcp_attr_error_code,
1179 { "Error Code", "xmcp.attr.error",
1180 FT_UINT16, BASE_DEC, VALS(error_codes), 0x0, NULL, HFILL}
1182 { &xmcp_attr_error_reason,
1183 { "Error Reason Phrase", "xmcp.attr.error.reason",
1184 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
1187 { "Realm", "xmcp.attr.realm",
1188 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1191 { "Nonce", "xmcp.attr.nonce",
1192 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1194 { &xmcp_attr_client_name,
1195 { "Client-Name", "xmcp.attr.client-name",
1196 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1198 { &xmcp_attr_client_handle,
1199 { "Client-Handle", "xmcp.attr.client-handle",
1200 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1202 { &xmcp_attr_version_major,
1203 { "Protocol Major Version", "xmcp.attr.version.major",
1204 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1206 { &xmcp_attr_version_minor,
1207 { "Protocol Minor Version", "xmcp.attr.version.minor",
1208 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1210 { &xmcp_attr_page_size,
1211 { "Page-Size", "xmcp.attr.page-size",
1212 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1214 { &xmcp_attr_client_label,
1215 { "Client-Label", "xmcp.attr.client-label",
1216 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1218 { &xmcp_attr_keepalive,
1219 { "Keepalive", "xmcp.attr.keepalive",
1220 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1222 { &xmcp_attr_serv_service,
1223 { "Service ID", "xmcp.attr.service.service",
1224 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1226 { &xmcp_attr_serv_subservice,
1227 { "Subservice ID", "xmcp.attr.service.subservice",
1228 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1230 { &xmcp_attr_serv_instance,
1231 { "Instance ID", "xmcp.attr.service.instance",
1232 FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }
1234 { &xmcp_attr_servtrans_family,
1235 { "Family", "xmcp.attr.service.transport.family",
1236 FT_UINT8, BASE_HEX, VALS(address_families), 0x0, NULL, HFILL }
1238 { &xmcp_attr_servtrans_port,
1239 { "Port", "xmcp.attr.service.transport.port",
1240 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1242 { &xmcp_attr_servtrans_ipv4,
1243 { "IPv4 Address", "xmcp.attr.service.transport.ipv4",
1244 FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
1246 { &xmcp_attr_servtrans_ipv6,
1247 { "IPv6 Address", "xmcp.attr.service.transport.ipv6",
1248 FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }
1250 { &xmcp_attr_service_protocol,
1251 { "Protocol", "xmcp.attr.service.transport.protocol",
1252 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &ipproto_val_ext,
1256 { "Flag", "xmcp.attr.flag",
1257 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
1259 { &xmcp_attr_flag_type,
1260 { "Flag Type", "xmcp.attr.flag.type",
1261 FT_UINT16, BASE_HEX, VALS(flag_types), 0x0, NULL, HFILL }
1263 { &xmcp_attr_flag_value,
1264 { "Flag Value", "xmcp.attr.flag.value",
1265 FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
1267 { &xmcp_attr_flag_removal_reason_network_withdraw,
1268 { "Network Withdraw",
1269 "xmcp.attr.flag.removal-reason.network-withdraw",
1270 FT_BOOLEAN, 16, TFS(&tfs_true_false),
1271 XMCP_REMOVAL_REASON_NETWORK_WITHDRAW, NULL, HFILL }
1273 { &xmcp_attr_flag_removal_reason_reserved,
1274 { "Reserved", "xmcp.attr.flag.removal-reason.reserved",
1275 FT_UINT16, BASE_HEX, NULL, XMCP_REMOVAL_REASON_RESERVED, NULL, HFILL }
1277 { &xmcp_attr_flag_trust,
1278 { "Trust", "xmcp.attr.flag.trust",
1279 FT_UINT16, BASE_HEX, VALS(flag_trust_values), 0x0, NULL, HFILL }
1281 { &xmcp_attr_flag_visibility_unauthenticated,
1282 { "Visible to Unauthenticated Clients",
1283 "xmcp.attr.flag.service-visibility.unauthenticated",
1284 FT_BOOLEAN, 16, TFS(&tfs_yes_no),
1285 XMCP_SERVICE_VISIBILITY_UNAUTHENTICATED, NULL, HFILL }
1287 { &xmcp_attr_flag_visibility_reserved,
1288 { "Reserved", "xmcp.attr.flag.service-visibility.reserved",
1289 FT_UINT16, BASE_HEX, NULL,
1290 XMCP_SERVICE_VISIBILITY_RESERVED, NULL, HFILL }
1292 { &xmcp_attr_service_version,
1293 { "Service Version", "xmcp.attr.service.version",
1294 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1296 { &xmcp_attr_service_data,
1297 { "Service Data", "xmcp.attr.service.data",
1298 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1300 { &xmcp_attr_subscription_id,
1301 { "Subscription ID", "xmcp.attr.subscription-id",
1302 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1304 { &xmcp_attr_service_removed_reason,
1305 { "Service Removed Reason", "xmcp.attr.service-removed-reason",
1306 FT_UINT32, BASE_DEC, VALS(service_removed_reasons), 0x0, NULL, HFILL }
1308 { &xmcp_attr_domain,
1309 { "Domain", "xmcp.attr.domain",
1310 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1314 /* Setup protocol subtree array */
1315 static gint *ett[] = {
1323 static ei_register_info ei[] = {
1324 { &ei_xmcp_data_following_message_integrity, { "xmcp.data_following_message_integrity", PI_PROTOCOL, PI_WARN, "Data following message-integrity", EXPFILL }},
1325 { &ei_xmcp_attr_error_number_out_of_range, { "xmcp.attr.error.number.out_of_range", PI_PROTOCOL, PI_WARN, "Error number out of 0-99 range", EXPFILL }},
1326 { &ei_xmcp_attr_error_code_unusual, { "xmcp.attr.error.unusual", PI_RESPONSE_CODE, PI_WARN, "Unusual error code", EXPFILL }},
1327 { &ei_xmcp_attr_realm_incorrect, { "xmcp.attr.realm.incorrect", PI_PROTOCOL, PI_WARN, "Incorrect Realm", EXPFILL }},
1328 { &ei_xmcp_attr_length_bad, { "xmcp.attr.length.bad", PI_PROTOCOL, PI_WARN, "Malformed IPv4 address", EXPFILL }},
1329 { &ei_xmcp_xmcp_attr_servtrans_unknown, { "xmcp.attr.service.transport.unknown", PI_PROTOCOL, PI_WARN, "Unknown transport type", EXPFILL }},
1330 { &ei_xmcp_attr_type_unknown, { "xmcp.attr.type.unknown", PI_PROTOCOL, PI_NOTE, "Unrecognized attribute type", EXPFILL }},
1331 { &ei_xmcp_type_reserved_not_zero, { "xmcp.type.reserved.not_zero", PI_PROTOCOL, PI_WARN, "First two bits not zero", EXPFILL }},
1332 { &ei_xmcp_message_class_reserved, { "xmcp.message_class.reserved", PI_PROTOCOL, PI_WARN, "Reserved message class", EXPFILL }},
1333 { &ei_xmcp_error_response, { "xmcp.error_response", PI_RESPONSE_CODE, PI_NOTE, "Error Response", EXPFILL }},
1334 { &ei_xmcp_msg_type_method_reserved, { "xmcp.msg_type_method.reserved", PI_PROTOCOL, PI_WARN, "Reserved message method", EXPFILL }},
1335 { &ei_xmcp_length_bad, { "xmcp.length.bad", PI_PROTOCOL, PI_ERROR, "XMCP message length exceeds packet length", EXPFILL }},
1336 { &ei_xmcp_magic_cookie_incorrect, { "xmcp.cookie.incorrect", PI_PROTOCOL, PI_WARN, "Magic cookie not correct for XMCP", EXPFILL }},
1337 { &ei_xmcp_response_without_request, { "xmcp.response_without_request", PI_SEQUENCE, PI_NOTE, "Response without corresponding request", EXPFILL }},
1338 { &ei_xmcp_new_session, { "xmcp.new_session", PI_SEQUENCE, PI_CHAT, "New session - Register", EXPFILL }},
1339 { &ei_xmcp_session_termination, { "xmcp.session_termination", PI_SEQUENCE, PI_CHAT, "Session termination", EXPFILL }},
1342 module_t *xmcp_module;
1343 expert_module_t* expert_xmcp;
1345 proto_xmcp = proto_register_protocol("eXtensible Messaging Client Protocol",
1348 proto_register_field_array(proto_xmcp, hf, array_length(hf));
1349 proto_register_subtree_array(ett, array_length(ett));
1350 expert_xmcp = expert_register_protocol(proto_xmcp);
1351 expert_register_field_array(expert_xmcp, ei, array_length(ei));
1353 /* Register XMCP configuration options */
1354 xmcp_module = prefs_register_protocol(proto_xmcp, proto_reg_handoff_xmcp);
1356 prefs_register_uint_preference(xmcp_module, "tcp.port", "XMCP TCP Port",
1357 "Set the port for XMCP messages (if other"
1358 " than the default of 4788)",
1359 10, &global_xmcp_tcp_port);
1364 proto_reg_handoff_xmcp(void)
1366 static gboolean xmcp_prefs_initialized = FALSE;
1367 static dissector_handle_t xmcp_tcp_handle;
1368 static guint xmcp_tcp_port;
1370 if (!xmcp_prefs_initialized) {
1371 xmcp_tcp_handle = new_create_dissector_handle(dissect_xmcp_tcp, proto_xmcp);
1372 heur_dissector_add("tcp", dissect_xmcp_heur, proto_xmcp);
1373 media_type_dissector_table = find_dissector_table("media_type");
1374 xmcp_prefs_initialized = TRUE;
1376 dissector_delete_uint("tcp.port", xmcp_tcp_port, xmcp_tcp_handle);
1379 xmcp_tcp_port = global_xmcp_tcp_port;
1380 dissector_add_uint("tcp.port", global_xmcp_tcp_port, xmcp_tcp_handle);
1384 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1389 * indent-tabs-mode: nil
1392 * vi: set shiftwidth=2 tabstop=8 expandtab:
1393 * :indentSize=2:tabSize=8:noTabs=true: