epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-xmcp.c
blob961df3ed38838c008ea3201e3af95b721ac2637c
1 /* packet-xmcp.c
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 * SPDX-License-Identifier: GPL-2.0-or-later
14 * XMCP is a proprietary Cisco protocol based very loosely on the
15 * Session Traversal Utilities for NAT (STUN) protocol.
16 * This dissector is capable of understanding XMCP versions 1.0 and 2.0.
19 #include "config.h"
21 #include <epan/packet.h>
22 #include <epan/ipproto.h>
23 #include <epan/addr_resolv.h>
24 #include <epan/expert.h>
25 #include <epan/tfs.h>
26 #include <wsutil/array.h>
27 #include "packet-tcp.h"
29 void proto_register_xmcp(void);
31 static dissector_table_t media_type_dissector_table;
33 /* Initialize the protocol and registered fields */
34 static int proto_xmcp;
36 static int hf_xmcp_response_in;
37 static int hf_xmcp_response_to;
38 static int hf_xmcp_time;
40 typedef struct _xmcp_transaction_t {
41 uint32_t request_frame;
42 uint32_t response_frame;
43 nstime_t request_time;
44 bool request_is_keepalive;
45 } xmcp_transaction_t;
47 typedef struct _xmcp_conv_info_t {
48 wmem_tree_t *transaction_pdus;
49 } xmcp_conv_info_t;
51 static int hf_xmcp_type;
52 static int hf_xmcp_type_reserved;
53 static int hf_xmcp_type_class;
54 static int hf_xmcp_type_method;
55 static int hf_xmcp_length;
56 static int hf_xmcp_cookie;
57 static int hf_xmcp_id;
58 static int hf_xmcp_attributes;
59 static int hf_xmcp_attr;
60 static int hf_xmcp_msg_is_keepalive;
62 static int hf_xmcp_attr_type;
63 static int hf_xmcp_attr_length;
64 static int hf_xmcp_attr_value; /* generic value for unrecognized attrs */
65 static int hf_xmcp_attr_padding; /* generic value for TLV padding bytes */
66 static int hf_xmcp_attr_reserved;
67 static int hf_xmcp_attr_username;
68 static int hf_xmcp_attr_message_integrity;
69 static int hf_xmcp_attr_error_reserved;
70 static int hf_xmcp_attr_error_class;
71 static int hf_xmcp_attr_error_number;
72 static int hf_xmcp_attr_error_code;
73 static int hf_xmcp_attr_error_reason;
74 static int hf_xmcp_attr_realm;
75 static int hf_xmcp_attr_nonce;
76 static int hf_xmcp_attr_client_name;
77 static int hf_xmcp_attr_client_handle;
78 static int hf_xmcp_attr_version_major;
79 static int hf_xmcp_attr_version_minor;
80 static int hf_xmcp_attr_page_size;
81 static int hf_xmcp_attr_client_label;
82 static int hf_xmcp_attr_keepalive;
83 static int hf_xmcp_attr_serv_service;
84 static int hf_xmcp_attr_serv_subservice;
85 static int hf_xmcp_attr_serv_instance;
86 static int hf_xmcp_attr_servtrans_family;
87 static int hf_xmcp_attr_servtrans_port;
88 static int hf_xmcp_attr_servtrans_ipv4;
89 static int hf_xmcp_attr_servtrans_ipv6;
90 static int hf_xmcp_attr_service_protocol;
91 static int hf_xmcp_attr_flag;
92 static int hf_xmcp_attr_flag_type;
93 static int hf_xmcp_attr_flag_value;
94 static int hf_xmcp_attr_flag_removal_reason_network_withdraw;
95 static int hf_xmcp_attr_flag_removal_reason_reserved;
96 static int hf_xmcp_attr_flag_trust;
97 static int hf_xmcp_attr_flag_visibility_unauthenticated;
98 static int hf_xmcp_attr_flag_visibility_reserved;
99 static int hf_xmcp_attr_service_version;
100 static int hf_xmcp_attr_service_data;
101 static int hf_xmcp_attr_subscription_id;
102 static int hf_xmcp_attr_service_removed_reason;
103 static int hf_xmcp_attr_domain;
105 static int ett_xmcp;
106 static int ett_xmcp_type;
107 static int ett_xmcp_attr_all;
108 static int ett_xmcp_attr;
109 static int ett_xmcp_attr_flag;
111 static expert_field ei_xmcp_message_class_reserved;
112 static expert_field ei_xmcp_attr_length_bad;
113 static expert_field ei_xmcp_attr_error_number_out_of_range;
114 static expert_field ei_xmcp_type_reserved_not_zero;
115 static expert_field ei_xmcp_data_following_message_integrity;
116 static expert_field ei_xmcp_msg_type_method_reserved;
117 static expert_field ei_xmcp_xmcp_attr_servtrans_unknown;
118 static expert_field ei_xmcp_attr_realm_incorrect;
119 static expert_field ei_xmcp_new_session;
120 static expert_field ei_xmcp_response_without_request;
121 static expert_field ei_xmcp_length_bad;
122 static expert_field ei_xmcp_error_response;
123 static expert_field ei_xmcp_magic_cookie_incorrect;
124 static expert_field ei_xmcp_attr_type_unknown;
125 static expert_field ei_xmcp_session_termination;
126 static expert_field ei_xmcp_attr_error_code_unusual;
128 #define TCP_PORT_XMCP 4788
129 #define XMCP_MAGIC_COOKIE 0x7f5a9bc7
131 void proto_reg_handoff_xmcp(void);
133 static dissector_handle_t xmcp_tcp_handle;
135 #define XMCP_HDR_LEN 20
136 #define XMCP_ATTR_HDR_LEN 4
138 #define XMCP_TYPE_RESERVED 0xc000
139 #define XMCP_TYPE_CLASS 0x0110
140 #define XMCP_TYPE_METHOD 0x3eef
142 static int * const xmcp_type_fields[] = {
143 &hf_xmcp_type_reserved,
144 &hf_xmcp_type_method,
145 &hf_xmcp_type_class,
146 NULL
149 #define XMCP_CLASS_REQUEST 0x00
150 #define XMCP_CLASS_RESERVED 0x01
151 #define XMCP_CLASS_RESPONSE_SUCCESS 0x10
152 #define XMCP_CLASS_RESPONSE_ERROR 0x11
154 static const value_string classes[] = {
155 {XMCP_CLASS_REQUEST, "Request"},
156 {XMCP_CLASS_RESERVED, "RESERVED-CLASS"},
157 {XMCP_CLASS_RESPONSE_SUCCESS, "Success Response"},
158 {XMCP_CLASS_RESPONSE_ERROR, "Error Response"},
159 {0, NULL}
162 #define XMCP_METHOD_ILLEGAL 0x000
163 #define XMCP_METHOD_REGISTER 0x001
164 #define XMCP_METHOD_UNREGISTER 0x002
165 #define XMCP_METHOD_REG_REVOKE 0x003
166 #define XMCP_METHOD_PUBLISH 0x004
167 #define XMCP_METHOD_UNPUBLISH 0x005
168 #define XMCP_METHOD_PUB_REVOKE 0x006
169 #define XMCP_METHOD_SUBSCRIBE 0x007
170 #define XMCP_METHOD_UNSUBSCRIBE 0x008
171 #define XMCP_METHOD_WITHDRAW 0x009
172 #define XMCP_METHOD_NOTIFY 0x00a
173 #define XMCP_METHOD_KEEPALIVE 0x00b
175 static const value_string methods[] = {
176 {XMCP_METHOD_ILLEGAL, "Illegal"},
177 {XMCP_METHOD_REGISTER, "Register"},
178 {XMCP_METHOD_UNREGISTER, "Unregister"},
179 {XMCP_METHOD_REG_REVOKE, "RegisterRevoke"},
180 {XMCP_METHOD_PUBLISH, "Publish"},
181 {XMCP_METHOD_UNPUBLISH, "Unpublish"},
182 {XMCP_METHOD_PUB_REVOKE, "PublishRevoke"},
183 {XMCP_METHOD_SUBSCRIBE, "Subscribe"},
184 {XMCP_METHOD_UNSUBSCRIBE, "Unsubscribe"},
185 {XMCP_METHOD_WITHDRAW, "Withdraw"},
186 {XMCP_METHOD_NOTIFY, "Notify"},
187 {XMCP_METHOD_KEEPALIVE, "Keepalive"},
188 {0, NULL}
191 #define XMCP_USERNAME 0x0006
192 #define XMCP_MESSAGE_INTEGRITY 0x0008
193 #define XMCP_ERROR_CODE 0x0009
194 #define XMCP_REALM 0x0014
195 #define XMCP_NONCE 0x0015
196 #define XMCP_CLIENT_NAME 0x1001
197 #define XMCP_CLIENT_HANDLE 0x1002
198 #define XMCP_PROTOCOL_VERSION 0x1003
199 #define XMCP_PAGE_SIZE 0x1004
200 #define XMCP_CLIENT_LABEL 0x1005
201 #define XMCP_KEEPALIVE 0x1006
202 #define XMCP_SERVICE_IDENTITY 0x1007
203 #define XMCP_SERVICE_TRANSPORT 0x1008
204 #define XMCP_SERVICE_PROTOCOL 0x1009
205 #define XMCP_FLAGS 0x100a
206 #define XMCP_SERVICE_VERSION 0x100b
207 #define XMCP_SERVICE_DATA 0x100c
208 #define XMCP_SUBSCRIPTION_ID 0x100e
209 #define XMCP_SERVICE_REMOVED_REASON 0x100f
210 #define XMCP_DOMAIN 0x1011
212 static const value_string attributes[] = {
213 /* Attributes inherited from STUN */
214 {XMCP_USERNAME, "Username"},
215 {XMCP_MESSAGE_INTEGRITY, "Message-Integrity"},
216 {XMCP_ERROR_CODE, "Error-Code"},
217 {XMCP_REALM, "Realm"},
218 {XMCP_NONCE, "Nonce"},
219 /* Attributes specific to XMCP */
220 {XMCP_CLIENT_NAME, "Client-Name"},
221 {XMCP_CLIENT_HANDLE, "Client-Handle"},
222 {XMCP_PROTOCOL_VERSION, "Protocol-Version"},
223 {XMCP_PAGE_SIZE, "PageSize"},
224 {XMCP_CLIENT_LABEL, "ClientLabel"},
225 {XMCP_KEEPALIVE, "Keepalive"},
226 {XMCP_SERVICE_IDENTITY, "ServiceIdentity"},
227 {XMCP_SERVICE_TRANSPORT, "ServiceTransportAddr"},
228 {XMCP_SERVICE_PROTOCOL, "ServiceProtocol"},
229 {XMCP_FLAGS, "Flags"},
230 {XMCP_SERVICE_VERSION, "ServiceVersion"},
231 {XMCP_SERVICE_DATA, "ServiceData"},
232 {XMCP_SUBSCRIPTION_ID, "SubscriptionID"},
233 {XMCP_SERVICE_REMOVED_REASON, "ServiceRemovedReason"},
234 {XMCP_DOMAIN, "Domain"},
235 {0, NULL}
238 static const value_string error_codes[] = {
239 {400, "Bad Request"},
240 {401, "Unauthorized"},
241 {413, "Request Too Large"},
242 {431, "Integrity Check Failure"},
243 {435, "Nonce Required"},
244 {436, "Unknown Username"},
245 {438, "Stale Nonce"},
246 {471, "Bad Client Handle"},
247 {472, "Version Number Too Low"},
248 {473, "Unknown Service"},
249 {474, "Unregistered"},
250 {475, "Invalid ServiceIdentity"},
251 {476, "Unknown Subscription"},
252 {477, "Already Registered"},
253 {478, "Unsupported Protocol Version"},
254 {479, "Unknown or Forbidden Domain"},
255 {499, "Miscellaneous Request Error"},
256 {500, "Responder Error"},
257 {501, "Not Implemented"},
258 {0, NULL}
261 static const value_string address_families[] = {
262 {0x01, "IPv4"},
263 {0x02, "IPv6"},
264 {0, NULL}
267 #define XMCP_FLAG_REMOVAL_REASON 0x0001
268 #define XMCP_FLAG_TRUST 0x0002
269 #define XMCP_FLAG_SERVICE_VISIBILITY 0x0003
271 static const value_string flag_types[] = {
272 {XMCP_FLAG_REMOVAL_REASON, "Removal Reason"},
273 {XMCP_FLAG_TRUST, "Trust"},
274 {XMCP_FLAG_SERVICE_VISIBILITY, "Service Visibility"},
275 {0, NULL}
278 /* Values for specific flag types */
279 #define XMCP_REMOVAL_REASON_NETWORK_WITHDRAW 0x0001
280 #define XMCP_REMOVAL_REASON_RESERVED 0xfffe
282 #define XMCP_TRUST_LOCAL 0
283 #define XMCP_TRUST_LEARNED 1
285 static const value_string flag_trust_values[] = {
286 {XMCP_TRUST_LOCAL, "Local"},
287 {XMCP_TRUST_LEARNED, "Learned"},
288 {0, NULL}
291 #define XMCP_SERVICE_VISIBILITY_UNAUTHENTICATED 0x0001
292 #define XMCP_SERVICE_VISIBILITY_RESERVED 0xfffe
294 static const value_string service_removed_reasons[] = {
295 {0, "Network withdraw"},
296 {1, "Source withdraw"},
297 {0, NULL}
300 /* Dissector state variables */
301 static uint16_t xmcp_msg_type_method = XMCP_METHOD_ILLEGAL;
302 static uint16_t xmcp_msg_type_class = XMCP_CLASS_RESERVED;
303 static bool xmcp_msg_is_keepalive;
304 static int16_t xmcp_service_protocol = -1;
305 static int32_t xmcp_service_port = -1;
306 static proto_item *xmcp_it_service_port;
308 static unsigned
309 get_xmcp_message_len(packet_info *pinfo _U_, tvbuff_t *tvb,
310 int offset, void *data _U_)
312 return XMCP_HDR_LEN + tvb_get_ntohs(tvb, offset+2);
315 static uint16_t
316 get_xmcp_attr_padded_len(uint16_t attr_length)
319 * As in STUN, all XMCP attributes report their length in bytes,
320 * but are padded to the next 4-byte multiple.
322 return (attr_length + 3) & 0xfffc;
325 static uint16_t
326 get_xmcp_attr_fixed_len(uint16_t xmcp_attr)
329 * For fixed-length attributes, return their length.
330 * For variable-length attributes, return 0.
332 switch (xmcp_attr) {
333 case XMCP_CLIENT_HANDLE:
334 case XMCP_PROTOCOL_VERSION:
335 case XMCP_PAGE_SIZE:
336 case XMCP_KEEPALIVE:
337 case XMCP_SERVICE_PROTOCOL:
338 case XMCP_SERVICE_VERSION:
339 case XMCP_SUBSCRIPTION_ID:
340 case XMCP_SERVICE_REMOVED_REASON:
341 case XMCP_DOMAIN:
342 return 4;
343 case XMCP_SERVICE_IDENTITY:
344 return 20;
345 default:
346 return 0;
350 static uint16_t
351 get_xmcp_attr_min_len(uint16_t xmcp_attr)
353 switch (xmcp_attr) {
354 case XMCP_USERNAME:
355 case XMCP_NONCE:
356 case XMCP_CLIENT_NAME:
357 case XMCP_CLIENT_LABEL:
358 return 1;
359 case XMCP_ERROR_CODE:
360 return 4;
361 case XMCP_SERVICE_TRANSPORT:
362 return 8; /* 4-byte fixed plus an IPv4 address */
363 case XMCP_MESSAGE_INTEGRITY:
364 return 20; /* HMAC-SHA1 */
365 default:
366 return get_xmcp_attr_fixed_len(xmcp_attr);
370 static uint16_t
371 get_xmcp_attr_max_len(uint16_t xmcp_attr) {
372 uint16_t fixed_len;
374 switch (xmcp_attr) {
375 case XMCP_SERVICE_TRANSPORT:
376 return 20; /* 4-byte fixed plus an IPv6 address */
377 case XMCP_MESSAGE_INTEGRITY:
378 return 32; /* HMAC-SHA-256 */
379 case XMCP_NONCE:
380 case XMCP_CLIENT_NAME:
381 case XMCP_CLIENT_LABEL:
382 return 255;
383 default:
384 fixed_len = get_xmcp_attr_fixed_len(xmcp_attr);
385 return fixed_len ? fixed_len : 0xffff;
389 static void
390 add_xmcp_port_name (packet_info *pinfo)
392 if (!xmcp_it_service_port || xmcp_service_port == -1)
393 return;
395 switch(xmcp_service_protocol) {
396 case IP_PROTO_TCP:
397 proto_item_append_text(xmcp_it_service_port, " (TCP: %s)", tcp_port_to_display(pinfo->pool, xmcp_service_port));
398 break;
399 case IP_PROTO_UDP:
400 proto_item_append_text(xmcp_it_service_port, " (UDP: %s)", udp_port_to_display(pinfo->pool, xmcp_service_port));
401 break;
402 case IP_PROTO_DCCP:
403 proto_item_append_text(xmcp_it_service_port, " (DCCP: %s)", dccp_port_to_display(pinfo->pool, xmcp_service_port));
404 break;
405 case IP_PROTO_SCTP:
406 proto_item_append_text(xmcp_it_service_port, " (SCTP: %s)", sctp_port_to_display(pinfo->pool, xmcp_service_port));
407 break;
408 default:
409 break;
413 static void
414 decode_xmcp_attr_value (proto_tree *attr_tree, uint16_t attr_type,
415 uint16_t attr_length, tvbuff_t *tvb, uint16_t offset,
416 packet_info *pinfo)
418 proto_item *it;
420 switch (attr_type) {
421 case XMCP_USERNAME:
422 proto_tree_add_item(attr_tree, hf_xmcp_attr_username, tvb, offset,
423 attr_length, ENC_ASCII);
424 proto_item_append_text(attr_tree, ": %s",
425 tvb_get_string_enc(pinfo->pool, tvb, offset, attr_length, ENC_ASCII));
427 * Many message methods may include this attribute,
428 * but it's only interesting when Registering at first
430 if (xmcp_msg_type_method == XMCP_METHOD_REGISTER) {
431 col_append_fstr(pinfo->cinfo, COL_INFO, ", user \"%s\"",
432 tvb_get_string_enc(pinfo->pool, tvb, offset, attr_length, ENC_ASCII));
434 break;
435 case XMCP_MESSAGE_INTEGRITY:
436 proto_tree_add_item(attr_tree, hf_xmcp_attr_message_integrity, tvb, offset,
437 attr_length, ENC_NA);
438 /* Message-integrity should be the last attribute in the message */
439 if ((unsigned)(offset + get_xmcp_attr_padded_len(attr_length)) < tvb_reported_length(tvb)) {
440 expert_add_info(pinfo, attr_tree, &ei_xmcp_data_following_message_integrity);
442 break;
443 case XMCP_ERROR_CODE:
444 if (attr_length < 4)
445 break;
446 proto_tree_add_item(attr_tree, hf_xmcp_attr_error_reserved, tvb, offset,
447 3, ENC_BIG_ENDIAN);
448 proto_tree_add_item(attr_tree, hf_xmcp_attr_error_class, tvb, offset,
449 3, ENC_BIG_ENDIAN);
451 uint8_t error_class, error_number;
452 uint16_t error_code;
453 it = proto_tree_add_item(attr_tree, hf_xmcp_attr_error_number, tvb,
454 (offset+3), 1, ENC_BIG_ENDIAN);
456 error_class = tvb_get_uint8(tvb, offset+2) & 0x07;
457 error_number = tvb_get_uint8(tvb, offset+3);
459 if (error_number > 99) {
460 expert_add_info(pinfo, it, &ei_xmcp_attr_error_number_out_of_range);
461 } else {
462 /* Error code = error class + (error num % 100) */
463 error_code = (error_class * 100) + error_number;
464 it = proto_tree_add_uint(attr_tree, hf_xmcp_attr_error_code, tvb,
465 (offset+2), 2, error_code);
466 proto_item_set_generated(it);
467 proto_item_append_text(attr_tree, ": %d", error_code);
468 col_append_fstr(pinfo->cinfo, COL_INFO, ", error %d (%s)", error_code,
469 val_to_str_const(error_code, error_codes, "Unknown"));
472 * All error responses default to a PI_NOTE severity.
473 * Some specific error codes are more significant, so mark them up.
475 switch (error_code) {
476 case 400: /* Bad Request */
477 case 431: /* Integrity Check Failure */
478 case 473: /* Unknown Service */
479 case 476: /* Unknown Subscription */
480 case 477: /* Already Registered */
481 case 499: /* Miscellaneous Request Error */
482 case 500: /* Responder Error */
483 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"));
484 break;
485 default:
486 break;
490 if (attr_length < 5)
491 break;
492 proto_tree_add_item(attr_tree, hf_xmcp_attr_error_reason, tvb, (offset+4),
493 (attr_length - 4), ENC_ASCII);
494 proto_item_append_text(attr_tree, " (%s)",
495 tvb_get_string_enc(pinfo->pool, tvb, (offset+4),
496 (attr_length-4), ENC_ASCII));
497 break;
498 case XMCP_REALM:
499 it = proto_tree_add_item(attr_tree, hf_xmcp_attr_realm, tvb, offset,
500 attr_length, ENC_ASCII);
502 uint8_t *realm;
503 realm = tvb_get_string_enc(pinfo->pool, tvb, offset, attr_length, ENC_ASCII);
504 proto_item_append_text(attr_tree, ": %s", realm);
505 /* In XMCP the REALM string should always be "SAF" including the quotes */
506 if (attr_length != 5 || strncmp(realm, "\"SAF\"", attr_length)) {
507 expert_add_info(pinfo, it, &ei_xmcp_attr_realm_incorrect);
510 break;
511 case XMCP_NONCE:
512 proto_tree_add_item(attr_tree, hf_xmcp_attr_nonce, tvb, offset,
513 attr_length, ENC_ASCII);
514 proto_item_append_text(attr_tree, ": %s",
515 tvb_get_string_enc(pinfo->pool, tvb, offset, attr_length, ENC_ASCII));
516 break;
517 case XMCP_CLIENT_NAME:
518 proto_tree_add_item(attr_tree, hf_xmcp_attr_client_name, tvb, offset,
519 attr_length, ENC_ASCII);
520 proto_item_append_text(attr_tree, ": %s",
521 tvb_get_string_enc(pinfo->pool, tvb, offset, attr_length, ENC_ASCII));
522 col_append_fstr(pinfo->cinfo, COL_INFO, ", name \"%s\"",
523 tvb_get_string_enc(pinfo->pool, tvb, offset, attr_length, ENC_ASCII));
524 break;
525 case XMCP_CLIENT_HANDLE:
526 if (attr_length < 4)
527 break;
528 proto_tree_add_item(attr_tree, hf_xmcp_attr_client_handle, tvb, offset,
529 4, ENC_BIG_ENDIAN);
530 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
531 col_append_fstr(pinfo->cinfo, COL_INFO, ", handle %u",
532 tvb_get_ntohl(tvb, offset));
534 * A Register request containing a Client-Handle is considered
535 * to be a Keepalive.
537 if (xmcp_msg_type_method == XMCP_METHOD_REGISTER &&
538 xmcp_msg_type_class == XMCP_CLASS_REQUEST) {
539 xmcp_msg_is_keepalive = true;
541 break;
542 case XMCP_PROTOCOL_VERSION:
543 if (attr_length < 2)
544 break;
545 proto_tree_add_item(attr_tree, hf_xmcp_attr_version_major, tvb, offset,
546 2, ENC_BIG_ENDIAN);
547 if (attr_length < 4)
548 break;
549 proto_tree_add_item(attr_tree, hf_xmcp_attr_version_minor, tvb, (offset+2),
550 2, ENC_BIG_ENDIAN);
551 proto_item_append_text(attr_tree, ": %u.%u", tvb_get_ntohs(tvb, offset),
552 tvb_get_ntohs(tvb, (offset+2)));
553 break;
554 case XMCP_PAGE_SIZE:
555 if (attr_length < 4)
556 break;
557 proto_tree_add_item(attr_tree, hf_xmcp_attr_page_size, tvb, offset, 4, ENC_BIG_ENDIAN);
558 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
559 break;
560 case XMCP_CLIENT_LABEL:
561 proto_tree_add_item(attr_tree, hf_xmcp_attr_client_label, tvb, offset,
562 attr_length, ENC_ASCII);
563 proto_item_append_text(attr_tree, ": %s",
564 tvb_get_string_enc(pinfo->pool, tvb, offset, attr_length, ENC_ASCII));
565 col_append_fstr(pinfo->cinfo, COL_INFO, ", label \"%s\"",
566 tvb_get_string_enc(pinfo->pool, tvb, offset, attr_length, ENC_ASCII));
567 break;
568 case XMCP_KEEPALIVE:
569 if (attr_length < 4)
570 break;
571 proto_tree_add_item(attr_tree, hf_xmcp_attr_keepalive, tvb, offset, 4, ENC_BIG_ENDIAN);
572 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
573 break;
574 case XMCP_SERVICE_IDENTITY:
575 if (attr_length < 2)
576 break;
577 proto_tree_add_item(attr_tree, hf_xmcp_attr_serv_service, tvb, offset,
578 2, ENC_BIG_ENDIAN);
579 if (attr_length < 4)
580 break;
581 proto_tree_add_item(attr_tree, hf_xmcp_attr_serv_subservice, tvb, (offset+2),
582 2, ENC_BIG_ENDIAN);
583 if (attr_length < 20)
584 break;
585 proto_tree_add_item(attr_tree, hf_xmcp_attr_serv_instance, tvb, (offset+4),
586 16, ENC_BIG_ENDIAN);
588 e_guid_t guid;
589 char buf[GUID_STR_LEN];
590 tvb_get_guid(tvb, (offset+4), &guid, ENC_BIG_ENDIAN);
591 guid_to_str_buf(&guid, buf, sizeof(buf));
592 proto_item_append_text(attr_tree, ": %u:%u:%s",
593 tvb_get_ntohs(tvb, offset),
594 tvb_get_ntohs(tvb, (offset+2)), buf);
595 col_append_fstr(pinfo->cinfo, COL_INFO, ", service %u:%u:%s",
596 tvb_get_ntohs(tvb, offset),
597 tvb_get_ntohs(tvb, (offset+2)), buf);
599 break;
600 case XMCP_SERVICE_TRANSPORT:
602 * One byte of padding, one byte indicating family,
603 * two bytes for port, followed by addr
605 if (attr_length < 1)
606 break;
607 proto_tree_add_item(attr_tree, hf_xmcp_attr_reserved, tvb, offset, 1, ENC_NA);
608 if (attr_length < 2)
609 break;
610 proto_tree_add_item(attr_tree, hf_xmcp_attr_servtrans_family, tvb,
611 (offset+1), 1, ENC_BIG_ENDIAN);
612 if (attr_length < 4)
613 break;
614 xmcp_service_port = tvb_get_ntohs(tvb, (offset+2));
615 xmcp_it_service_port = proto_tree_add_item(attr_tree,
616 hf_xmcp_attr_servtrans_port,
617 tvb, (offset+2), 2, ENC_BIG_ENDIAN);
618 /* If we now know both port and protocol number, fill in the port name */
619 if (xmcp_service_protocol != -1) {
620 add_xmcp_port_name(pinfo);
622 switch (tvb_get_uint8(tvb, (offset+1))) {
623 case 0x01: /* IPv4 */
624 if (attr_length != 8) {
625 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Malformed IPv4 address");
626 } else {
627 proto_tree_add_item(attr_tree, hf_xmcp_attr_servtrans_ipv4, tvb,
628 (offset+4), 4, ENC_BIG_ENDIAN);
629 proto_item_append_text(attr_tree, ": %s:%u", tvb_ip_to_str(pinfo->pool, tvb, offset+4),
630 tvb_get_ntohs(tvb, (offset+2)));
632 break;
633 case 0x02: /* IPv6 */
634 if (attr_length != 20) {
635 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Malformed IPv6 address");
636 } else {
637 proto_tree_add_item(attr_tree, hf_xmcp_attr_servtrans_ipv6, tvb,
638 (offset+4), 16, ENC_NA);
639 proto_item_append_text(attr_tree, ": [%s]:%u", tvb_ip6_to_str(pinfo->pool, tvb, (offset+4)),
640 tvb_get_ntohs(tvb, (offset+2)));
642 break;
643 default:
644 expert_add_info(pinfo, attr_tree, &ei_xmcp_xmcp_attr_servtrans_unknown);
645 break;
647 break;
648 case XMCP_SERVICE_PROTOCOL:
649 /* Three bytes of padding followed by a 1-byte protocol number */
650 if (attr_length < 4)
651 break;
652 proto_tree_add_item(attr_tree, hf_xmcp_attr_reserved, tvb, offset, 3, ENC_NA);
653 proto_tree_add_item(attr_tree, hf_xmcp_attr_service_protocol, tvb,
654 (offset+3), 1, ENC_BIG_ENDIAN);
655 xmcp_service_protocol = tvb_get_uint8(tvb, (offset+3));
656 proto_item_append_text(attr_tree, ": %u (%s)", xmcp_service_protocol,
657 val_to_str_ext_const(xmcp_service_protocol,
658 &ipproto_val_ext, "Unknown"));
659 /* If we now know both port and protocol number, fill in the port name */
660 if (xmcp_service_port != -1 && xmcp_it_service_port != NULL) {
661 add_xmcp_port_name(pinfo);
663 break;
664 case XMCP_FLAGS:
665 /* Flags is a series of type-value pairs */
666 if (attr_length % 4 != 0) {
667 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Malformed Flags - length not divisible by 4");
670 uint16_t flag_type, flag_value, current_offset = offset;
671 proto_item *ti;
672 proto_tree *flag_tree;
673 while ((current_offset-offset)+3 < attr_length) {
674 flag_type = tvb_get_ntohs(tvb, (current_offset));
675 flag_value = tvb_get_ntohs(tvb, (current_offset+2));
676 ti = proto_tree_add_none_format(attr_tree, hf_xmcp_attr_flag, tvb,
677 current_offset, 4,
678 "Flag: %s:",
679 val_to_str_const(flag_type, flag_types,
680 "Unknown"));
681 flag_tree = proto_item_add_subtree(ti, ett_xmcp_attr_flag);
682 proto_tree_add_item(flag_tree, hf_xmcp_attr_flag_type, tvb,
683 current_offset, 2, ENC_BIG_ENDIAN);
685 current_offset += 2;
686 switch (flag_type) {
687 case XMCP_FLAG_REMOVAL_REASON:
688 proto_tree_add_item(flag_tree, hf_xmcp_attr_flag_removal_reason_reserved,
689 tvb, current_offset, 2, ENC_BIG_ENDIAN);
690 proto_tree_add_item(flag_tree,
691 hf_xmcp_attr_flag_removal_reason_network_withdraw,
692 tvb, current_offset, 2, ENC_BIG_ENDIAN);
693 if (flag_value & XMCP_REMOVAL_REASON_NETWORK_WITHDRAW) {
694 proto_item_append_text(flag_tree, " (network withdraw)");
696 if (!flag_value) {
697 proto_item_append_text(flag_tree, " (source withdraw)");
699 break;
700 case XMCP_FLAG_TRUST:
701 proto_tree_add_item(flag_tree, hf_xmcp_attr_flag_trust, tvb,
702 current_offset, 2, ENC_BIG_ENDIAN);
703 proto_item_append_text(flag_tree, " %s",
704 val_to_str_const(flag_value, flag_trust_values,
705 "Unknown"));
706 break;
707 case XMCP_FLAG_SERVICE_VISIBILITY:
708 proto_tree_add_item(flag_tree, hf_xmcp_attr_flag_visibility_reserved,
709 tvb, current_offset, 2, ENC_BIG_ENDIAN);
710 proto_tree_add_item(flag_tree,
711 hf_xmcp_attr_flag_visibility_unauthenticated,
712 tvb, current_offset, 2, ENC_BIG_ENDIAN);
713 if (flag_value & XMCP_SERVICE_VISIBILITY_UNAUTHENTICATED) {
714 proto_item_append_text(flag_tree,
715 " (visible to unauthenticated clients)");
717 if (!flag_value) {
718 proto_item_append_text(flag_tree, " (default)");
720 break;
721 default:
722 proto_tree_add_item(flag_tree, hf_xmcp_attr_flag_value, tvb,
723 current_offset, 2, ENC_BIG_ENDIAN);
724 proto_item_append_text(flag_tree, " 0x%04x", flag_value);
725 break;
727 current_offset += 2;
730 break;
731 case XMCP_SERVICE_VERSION:
732 if (attr_length < 4)
733 break;
734 proto_tree_add_item(attr_tree, hf_xmcp_attr_service_version, tvb, offset,
735 4, ENC_BIG_ENDIAN);
736 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
737 break;
738 case XMCP_SERVICE_DATA:
739 proto_tree_add_item(attr_tree, hf_xmcp_attr_service_data, tvb, offset,
740 attr_length, ENC_NA);
741 if (attr_length > 0) {
742 tvbuff_t *next_tvb;
743 uint8_t *test_string, *tok;
745 next_tvb = tvb_new_subset_length(tvb, offset, attr_length);
747 * Service-Data is usually (but not always) plain text, specifically XML.
748 * If it "looks like" XML (begins with optional whitespace followed by
749 * a '<'), try XML.
750 * Otherwise, try plain-text.
752 test_string = tvb_get_string_enc(pinfo->pool, next_tvb, 0, (attr_length < 32 ?
753 attr_length : 32), ENC_ASCII);
754 tok = strtok(test_string, " \t\r\n");
755 if (tok && tok[0] == '<') {
756 /* Looks like XML */
757 dissector_try_string(media_type_dissector_table, "application/xml",
758 next_tvb, pinfo, attr_tree, NULL);
759 } else {
760 /* Try plain text */
761 dissector_try_string(media_type_dissector_table, "text/plain",
762 next_tvb, pinfo, attr_tree, NULL);
765 break;
766 case XMCP_SUBSCRIPTION_ID:
767 if (attr_length < 4)
768 break;
769 proto_tree_add_item(attr_tree, hf_xmcp_attr_subscription_id, tvb, offset,
770 4, ENC_BIG_ENDIAN);
771 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
772 col_append_fstr(pinfo->cinfo, COL_INFO, ", subscription %u",
773 tvb_get_ntohl(tvb, offset));
774 break;
775 case XMCP_SERVICE_REMOVED_REASON:
776 if (attr_length < 4)
777 break;
778 proto_tree_add_item(attr_tree, hf_xmcp_attr_service_removed_reason, tvb,
779 offset, 4, ENC_BIG_ENDIAN);
780 proto_item_append_text(attr_tree, ": %s",
781 val_to_str_const(tvb_get_ntohl(tvb, offset),
782 service_removed_reasons,
783 "Unknown"));
784 break;
785 case XMCP_DOMAIN:
786 if (attr_length < 4)
787 break;
788 proto_tree_add_item(attr_tree, hf_xmcp_attr_domain, tvb, offset, 4, ENC_BIG_ENDIAN);
789 proto_item_append_text(attr_tree, ": %u", tvb_get_ntohl(tvb, offset));
790 break;
791 default:
792 proto_tree_add_item(attr_tree, hf_xmcp_attr_value, tvb, offset,
793 attr_length, ENC_NA);
794 expert_add_info(pinfo, attr_tree, &ei_xmcp_attr_type_unknown);
795 break;
797 if (attr_length % 4 != 0) {
798 proto_tree_add_item(attr_tree, hf_xmcp_attr_padding, tvb, (offset+attr_length),
799 (4 - (attr_length % 4)), ENC_NA);
801 if (attr_length < get_xmcp_attr_min_len(attr_type)) {
802 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Length less than minimum for this attribute type");
803 } else if (attr_length > get_xmcp_attr_max_len(attr_type)) {
804 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Length exceeds maximum for this attribute type");
808 static int
809 dissect_xmcp_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
811 uint16_t msg_type, msg_length;
812 proto_item *ti = NULL;
813 proto_tree *xmcp_tree, *attr_all_tree, *attr_tree;
814 uint16_t offset, attr_type, attr_length;
816 /* For request/response association */
817 uint32_t transaction_id[3];
818 wmem_tree_key_t transaction_id_key[2];
819 conversation_t *conversation;
820 xmcp_conv_info_t *xmcp_conv_info;
821 xmcp_transaction_t *xmcp_trans;
823 if (tvb_reported_length(tvb) < XMCP_HDR_LEN) {
824 return 0;
826 /* Check for valid message type field */
827 msg_type = tvb_get_ntohs(tvb, 0);
828 if (msg_type & XMCP_TYPE_RESERVED) { /* First 2 bits must be 0 */
829 return 0;
831 /* Check for valid "magic cookie" field */
832 if (tvb_get_ntohl(tvb, 4) != XMCP_MAGIC_COOKIE) {
833 return 0;
836 col_set_str(pinfo->cinfo, COL_PROTOCOL, "XMCP");
837 /* Clear out stuff in the info column */
838 col_clear(pinfo->cinfo, COL_INFO);
840 /* As in STUN, the first 2 bytes contain the message class and method */
841 xmcp_msg_type_class = ((msg_type & XMCP_TYPE_CLASS) >> 4);
842 xmcp_msg_type_method = (msg_type & XMCP_TYPE_METHOD);
843 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
844 val_to_str_const(xmcp_msg_type_method, methods, "Unknown"),
845 val_to_str_const(xmcp_msg_type_class, classes, "Unknown"));
847 /* Get the transaction ID */
848 transaction_id[0] = tvb_get_ntohl(tvb, 8);
849 transaction_id[1] = tvb_get_ntohl(tvb, 12);
850 transaction_id[2] = tvb_get_ntohl(tvb, 16);
852 transaction_id_key[0].length = 3;
853 transaction_id_key[0].key = transaction_id;
854 transaction_id_key[1].length = 0;
855 transaction_id_key[1].key = NULL;
857 conversation = find_or_create_conversation(pinfo);
859 /* Do we already have XMCP state for this conversation? */
860 xmcp_conv_info = (xmcp_conv_info_t *)conversation_get_proto_data(conversation, proto_xmcp);
861 if (!xmcp_conv_info) {
862 xmcp_conv_info = wmem_new(wmem_file_scope(), xmcp_conv_info_t);
863 xmcp_conv_info->transaction_pdus = wmem_tree_new(wmem_file_scope());
864 conversation_add_proto_data(conversation, proto_xmcp, xmcp_conv_info);
867 /* Find existing transaction entry or create a new one */
868 xmcp_trans = (xmcp_transaction_t *)wmem_tree_lookup32_array(xmcp_conv_info->transaction_pdus,
869 transaction_id_key);
870 if (!xmcp_trans) {
871 xmcp_trans = wmem_new(wmem_file_scope(), xmcp_transaction_t);
872 xmcp_trans->request_frame = 0;
873 xmcp_trans->response_frame = 0;
874 xmcp_trans->request_time = pinfo->abs_ts;
875 xmcp_trans->request_is_keepalive = false;
876 wmem_tree_insert32_array(xmcp_conv_info->transaction_pdus,
877 transaction_id_key, (void *)xmcp_trans);
880 /* Update transaction entry */
881 if (!pinfo->fd->visited) {
882 if (xmcp_msg_type_class == XMCP_CLASS_REQUEST) {
883 if (xmcp_trans->request_frame == 0) {
884 xmcp_trans->request_frame = pinfo->num;
885 xmcp_trans->request_time = pinfo->abs_ts;
887 } else if (xmcp_msg_type_class != XMCP_CLASS_RESERVED) {
888 if (xmcp_trans->response_frame == 0) {
889 xmcp_trans->response_frame = pinfo->num;
894 ti = proto_tree_add_item(tree, proto_xmcp, tvb, 0, -1, ENC_NA);
895 xmcp_tree = proto_item_add_subtree(ti, ett_xmcp);
897 ti = proto_tree_add_bitmask(xmcp_tree, tvb, 0, hf_xmcp_type, ett_xmcp_type,
898 xmcp_type_fields, ENC_BIG_ENDIAN);
900 if (msg_type & XMCP_TYPE_RESERVED) {
901 expert_add_info(pinfo, ti, &ei_xmcp_type_reserved_not_zero);
903 if (xmcp_msg_type_class == XMCP_CLASS_RESERVED) {
904 expert_add_info(pinfo, ti, &ei_xmcp_message_class_reserved);
905 } else if (xmcp_msg_type_class == XMCP_CLASS_RESPONSE_ERROR) {
906 expert_add_info(pinfo, ti, &ei_xmcp_error_response);
909 if (xmcp_msg_type_method < 0x001 || xmcp_msg_type_method > 0x00b) {
910 expert_add_info(pinfo, ti, &ei_xmcp_msg_type_method_reserved);
914 * Some forms of XMCP overload the Register method for Keepalive packets
915 * rather than using a separate Keepalive method. We'll try to determine from
916 * the message contents whether this message is a Keepalive. Initialize first.
918 xmcp_msg_is_keepalive = (xmcp_trans->request_is_keepalive ||
919 (xmcp_msg_type_method == XMCP_METHOD_KEEPALIVE));
921 /* After the class/method, we have a 2 byte length...*/
922 ti = proto_tree_add_item(xmcp_tree, hf_xmcp_length, tvb, 2, 2, ENC_BIG_ENDIAN);
923 msg_length = tvb_get_ntohs(tvb, 2);
924 if ((unsigned)(msg_length + XMCP_HDR_LEN) > tvb_reported_length(tvb)) {
925 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));
926 return tvb_captured_length(tvb);
929 /* ...a 4 byte magic cookie... */
930 ti = proto_tree_add_item(xmcp_tree, hf_xmcp_cookie, tvb, 4, 4, ENC_BIG_ENDIAN);
931 if (tvb_get_ntohl(tvb, 4) != XMCP_MAGIC_COOKIE) {
932 expert_add_info(pinfo, ti, &ei_xmcp_magic_cookie_incorrect);
935 /* ...and a 12-byte transaction id */
936 ti = proto_tree_add_item(xmcp_tree, hf_xmcp_id, tvb, 8, 12, ENC_NA);
938 /* Print state tracking in the tree */
939 if (xmcp_msg_type_class == XMCP_CLASS_REQUEST) {
940 if (xmcp_trans->response_frame) {
941 ti = proto_tree_add_uint(xmcp_tree, hf_xmcp_response_in, tvb, 0, 0,
942 xmcp_trans->response_frame);
943 proto_item_set_generated(ti);
945 } else if (xmcp_msg_type_class != XMCP_CLASS_RESERVED) {
946 if (xmcp_trans->request_frame) {
947 nstime_t ns;
949 ti = proto_tree_add_uint(xmcp_tree, hf_xmcp_response_to, tvb, 0, 0,
950 xmcp_trans->request_frame);
951 proto_item_set_generated(ti);
953 nstime_delta(&ns, &pinfo->abs_ts, &xmcp_trans->request_time);
954 ti = proto_tree_add_time(xmcp_tree, hf_xmcp_time, tvb, 0, 0, &ns);
955 proto_item_set_generated(ti);
956 } else {
957 /* This is a response, but we don't know about a request for this response? */
958 expert_add_info(pinfo, ti, &ei_xmcp_response_without_request);
962 xmcp_service_protocol = -1;
963 xmcp_service_port = -1;
964 xmcp_it_service_port = NULL;
966 /* The header is then followed by "msg_length" bytes of TLV attributes */
967 if (msg_length > 0) {
968 ti = proto_tree_add_item(xmcp_tree, hf_xmcp_attributes, tvb,
969 XMCP_HDR_LEN, msg_length, ENC_NA);
970 attr_all_tree = proto_item_add_subtree(ti, ett_xmcp_attr_all);
972 offset = XMCP_HDR_LEN;
974 while (offset < (msg_length + XMCP_HDR_LEN)) {
975 /* Get type/length of next TLV */
976 attr_type = tvb_get_ntohs(tvb, offset);
977 attr_length = tvb_get_ntohs(tvb, offset+2);
978 ti = proto_tree_add_none_format(attr_all_tree, hf_xmcp_attr, tvb, offset,
979 (XMCP_ATTR_HDR_LEN +
980 get_xmcp_attr_padded_len(attr_length)),
981 "%s, length %u",
982 val_to_str_const(attr_type, attributes,
983 "Unknown"),
984 attr_length);
986 /* Add subtree for this TLV */
987 attr_tree = proto_item_add_subtree(ti, ett_xmcp_attr);
989 proto_tree_add_item(attr_tree, hf_xmcp_attr_type, tvb,
990 offset, 2, ENC_BIG_ENDIAN);
991 offset += 2;
992 ti = proto_tree_add_item(attr_tree, hf_xmcp_attr_length, tvb,
993 offset, 2, ENC_BIG_ENDIAN);
994 offset += 2;
996 if ((offset + attr_length) > (XMCP_HDR_LEN + msg_length)) {
997 proto_item_append_text(ti, " (bogus, exceeds message length)");
998 expert_add_info_format(pinfo, attr_tree, &ei_xmcp_attr_length_bad, "Attribute length exceeds message length");
999 break;
1002 decode_xmcp_attr_value(attr_tree, attr_type, attr_length, tvb,
1003 offset, pinfo);
1005 offset += get_xmcp_attr_padded_len(attr_length);
1010 * Flag this message as a keepalive if the attribute analysis
1011 * suggested that it is one
1013 if (xmcp_msg_is_keepalive) {
1014 ti = proto_tree_add_none_format(xmcp_tree, hf_xmcp_msg_is_keepalive, tvb,
1015 0, 0, "This is a Keepalive message");
1016 proto_item_set_generated(ti);
1017 if (xmcp_msg_type_method != XMCP_METHOD_KEEPALIVE) {
1018 col_prepend_fstr(pinfo->cinfo, COL_INFO, "[Keepalive] ");
1020 if (xmcp_msg_type_class == XMCP_CLASS_REQUEST) {
1021 xmcp_trans->request_is_keepalive = true;
1023 } else if (xmcp_msg_type_class == XMCP_CLASS_REQUEST ||
1024 xmcp_msg_type_class == XMCP_CLASS_RESPONSE_SUCCESS) {
1025 if (xmcp_msg_type_method == XMCP_METHOD_REGISTER) {
1026 expert_add_info_format(pinfo, xmcp_tree, &ei_xmcp_new_session, "New session - Register %s", val_to_str_const(xmcp_msg_type_class, classes, ""));
1027 } else if (xmcp_msg_type_method == XMCP_METHOD_UNREGISTER ||
1028 xmcp_msg_type_method == XMCP_METHOD_REG_REVOKE) {
1029 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, ""));
1033 return tvb_captured_length(tvb);
1036 static int
1037 dissect_xmcp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
1039 tcp_dissect_pdus(tvb, pinfo, tree, true, XMCP_HDR_LEN,
1040 get_xmcp_message_len, dissect_xmcp_message, data);
1041 return tvb_captured_length(tvb);
1044 static bool
1045 dissect_xmcp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1047 /* See if this looks like a real XMCP packet */
1048 if (tvb_captured_length(tvb) < XMCP_HDR_LEN) {
1049 return false;
1051 /* Check for valid message type field */
1052 if (tvb_get_ntohs(tvb, 0) & XMCP_TYPE_RESERVED) { /* First 2 bits must be 0 */
1053 return false;
1055 /* Check for valid "magic cookie" field */
1056 if (tvb_get_ntohl(tvb, 4) != XMCP_MAGIC_COOKIE) {
1057 return false;
1060 /* Good enough to consider a match! */
1061 tcp_dissect_pdus(tvb, pinfo, tree, true, XMCP_HDR_LEN,
1062 get_xmcp_message_len, dissect_xmcp_message, data);
1063 return true;
1066 void
1067 proto_register_xmcp(void)
1069 static hf_register_info hf[] = {
1070 { &hf_xmcp_type,
1071 { "Message Type", "xmcp.type",
1072 FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }
1074 { &hf_xmcp_type_reserved,
1075 { "Reserved", "xmcp.type.reserved",
1076 FT_UINT16, BASE_HEX, NULL, XMCP_TYPE_RESERVED, NULL, HFILL }
1078 { &hf_xmcp_type_class,
1079 { "Class", "xmcp.type.class",
1080 FT_UINT16, BASE_HEX, VALS(classes), XMCP_TYPE_CLASS, NULL, HFILL }
1082 { &hf_xmcp_type_method,
1083 { "Method", "xmcp.type.method",
1084 FT_UINT16, BASE_HEX, VALS(methods), XMCP_TYPE_METHOD, NULL, HFILL }
1086 { &hf_xmcp_msg_is_keepalive,
1087 { "Message is Keepalive", "xmcp.analysis.keepalive",
1088 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
1090 { &hf_xmcp_length,
1091 { "Message Length", "xmcp.length",
1092 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1094 { &hf_xmcp_cookie,
1095 { "XMCP Magic Cookie", "xmcp.cookie",
1096 FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }
1098 { &hf_xmcp_id,
1099 { "Transaction ID", "xmcp.id",
1100 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1102 { &hf_xmcp_response_in,
1103 { "Response In", "xmcp.response-in",
1104 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
1105 "The response to this XMCP request is in this frame", HFILL }
1107 { &hf_xmcp_response_to,
1108 { "Response To", "xmcp.response-to",
1109 FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
1110 "This is a response to the XMCP request in this frame", HFILL }
1112 { &hf_xmcp_time,
1113 { "Elapsed Time", "xmcp.time",
1114 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
1115 "The time between the Request and the Response", HFILL }
1117 { &hf_xmcp_attributes,
1118 { "Attributes", "xmcp.attributes",
1119 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
1121 { &hf_xmcp_attr,
1122 { "Attribute", "xmcp.attr",
1123 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
1125 { &hf_xmcp_attr_type,
1126 { "Attribute Type", "xmcp.attr.type",
1127 FT_UINT16, BASE_HEX, VALS(attributes), 0x0, NULL, HFILL }
1129 { &hf_xmcp_attr_length,
1130 { "Attribute Length", "xmcp.attr.length",
1131 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1133 { &hf_xmcp_attr_value,
1134 { "Attribute Value", "xmcp.attr.value",
1135 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}
1137 { &hf_xmcp_attr_padding,
1138 { "Padding", "xmcp.attr.padding",
1139 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1141 { &hf_xmcp_attr_reserved,
1142 { "Reserved", "xmcp.attr.reserved",
1143 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1145 { &hf_xmcp_attr_username,
1146 { "Username", "xmcp.attr.username",
1147 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1149 { &hf_xmcp_attr_message_integrity,
1150 { "Message-Integrity", "xmcp.attr.hmac",
1151 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1153 { &hf_xmcp_attr_error_reserved,
1154 { "Reserved", "xmcp.attr.error.reserved",
1155 FT_UINT24, BASE_HEX, NULL, 0xFFFFF8, NULL, HFILL }
1157 { &hf_xmcp_attr_error_class,
1158 { "Error Class", "xmcp.attr.error.class",
1159 FT_UINT24, BASE_DEC, NULL, 0x000007, NULL, HFILL}
1161 { &hf_xmcp_attr_error_number,
1162 { "Error Number", "xmcp.attr.error.number",
1163 FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
1165 { &hf_xmcp_attr_error_code,
1166 { "Error Code", "xmcp.attr.error",
1167 FT_UINT16, BASE_DEC, VALS(error_codes), 0x0, NULL, HFILL}
1169 { &hf_xmcp_attr_error_reason,
1170 { "Error Reason Phrase", "xmcp.attr.error.reason",
1171 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
1173 { &hf_xmcp_attr_realm,
1174 { "Realm", "xmcp.attr.realm",
1175 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1177 { &hf_xmcp_attr_nonce,
1178 { "Nonce", "xmcp.attr.nonce",
1179 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1181 { &hf_xmcp_attr_client_name,
1182 { "Client-Name", "xmcp.attr.client-name",
1183 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1185 { &hf_xmcp_attr_client_handle,
1186 { "Client-Handle", "xmcp.attr.client-handle",
1187 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1189 { &hf_xmcp_attr_version_major,
1190 { "Protocol Major Version", "xmcp.attr.version.major",
1191 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1193 { &hf_xmcp_attr_version_minor,
1194 { "Protocol Minor Version", "xmcp.attr.version.minor",
1195 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1197 { &hf_xmcp_attr_page_size,
1198 { "Page-Size", "xmcp.attr.page-size",
1199 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1201 { &hf_xmcp_attr_client_label,
1202 { "Client-Label", "xmcp.attr.client-label",
1203 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }
1205 { &hf_xmcp_attr_keepalive,
1206 { "Keepalive", "xmcp.attr.keepalive",
1207 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1209 { &hf_xmcp_attr_serv_service,
1210 { "Service ID", "xmcp.attr.service.service",
1211 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1213 { &hf_xmcp_attr_serv_subservice,
1214 { "Subservice ID", "xmcp.attr.service.subservice",
1215 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1217 { &hf_xmcp_attr_serv_instance,
1218 { "Instance ID", "xmcp.attr.service.instance",
1219 FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }
1221 { &hf_xmcp_attr_servtrans_family,
1222 { "Family", "xmcp.attr.service.transport.family",
1223 FT_UINT8, BASE_HEX, VALS(address_families), 0x0, NULL, HFILL }
1225 { &hf_xmcp_attr_servtrans_port,
1226 { "Port", "xmcp.attr.service.transport.port",
1227 FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }
1229 { &hf_xmcp_attr_servtrans_ipv4,
1230 { "IPv4 Address", "xmcp.attr.service.transport.ipv4",
1231 FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }
1233 { &hf_xmcp_attr_servtrans_ipv6,
1234 { "IPv6 Address", "xmcp.attr.service.transport.ipv6",
1235 FT_IPv6, BASE_NONE, NULL, 0x0, NULL, HFILL }
1237 { &hf_xmcp_attr_service_protocol,
1238 { "Protocol", "xmcp.attr.service.transport.protocol",
1239 FT_UINT8, BASE_DEC|BASE_EXT_STRING, &ipproto_val_ext,
1240 0x0, NULL, HFILL }
1242 { &hf_xmcp_attr_flag,
1243 { "Flag", "xmcp.attr.flag",
1244 FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }
1246 { &hf_xmcp_attr_flag_type,
1247 { "Flag Type", "xmcp.attr.flag.type",
1248 FT_UINT16, BASE_HEX, VALS(flag_types), 0x0, NULL, HFILL }
1250 { &hf_xmcp_attr_flag_value,
1251 { "Flag Value", "xmcp.attr.flag.value",
1252 FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL }
1254 { &hf_xmcp_attr_flag_removal_reason_network_withdraw,
1255 { "Network Withdraw",
1256 "xmcp.attr.flag.removal-reason.network-withdraw",
1257 FT_BOOLEAN, 16, NULL,
1258 XMCP_REMOVAL_REASON_NETWORK_WITHDRAW, NULL, HFILL }
1260 { &hf_xmcp_attr_flag_removal_reason_reserved,
1261 { "Reserved", "xmcp.attr.flag.removal-reason.reserved",
1262 FT_UINT16, BASE_HEX, NULL, XMCP_REMOVAL_REASON_RESERVED, NULL, HFILL }
1264 { &hf_xmcp_attr_flag_trust,
1265 { "Trust", "xmcp.attr.flag.trust",
1266 FT_UINT16, BASE_HEX, VALS(flag_trust_values), 0x0, NULL, HFILL }
1268 { &hf_xmcp_attr_flag_visibility_unauthenticated,
1269 { "Visible to Unauthenticated Clients",
1270 "xmcp.attr.flag.service-visibility.unauthenticated",
1271 FT_BOOLEAN, 16, TFS(&tfs_yes_no),
1272 XMCP_SERVICE_VISIBILITY_UNAUTHENTICATED, NULL, HFILL }
1274 { &hf_xmcp_attr_flag_visibility_reserved,
1275 { "Reserved", "xmcp.attr.flag.service-visibility.reserved",
1276 FT_UINT16, BASE_HEX, NULL,
1277 XMCP_SERVICE_VISIBILITY_RESERVED, NULL, HFILL }
1279 { &hf_xmcp_attr_service_version,
1280 { "Service Version", "xmcp.attr.service.version",
1281 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1283 { &hf_xmcp_attr_service_data,
1284 { "Service Data", "xmcp.attr.service.data",
1285 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }
1287 { &hf_xmcp_attr_subscription_id,
1288 { "Subscription ID", "xmcp.attr.subscription-id",
1289 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1291 { &hf_xmcp_attr_service_removed_reason,
1292 { "Service Removed Reason", "xmcp.attr.service-removed-reason",
1293 FT_UINT32, BASE_DEC, VALS(service_removed_reasons), 0x0, NULL, HFILL }
1295 { &hf_xmcp_attr_domain,
1296 { "Domain", "xmcp.attr.domain",
1297 FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }
1301 /* Setup protocol subtree array */
1302 static int *ett[] = {
1303 &ett_xmcp,
1304 &ett_xmcp_type,
1305 &ett_xmcp_attr_all,
1306 &ett_xmcp_attr,
1307 &ett_xmcp_attr_flag
1310 static ei_register_info ei[] = {
1311 { &ei_xmcp_data_following_message_integrity, { "xmcp.data_following_message_integrity", PI_PROTOCOL, PI_WARN, "Data following message-integrity", EXPFILL }},
1312 { &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 }},
1313 { &ei_xmcp_attr_error_code_unusual, { "xmcp.attr.error.unusual", PI_RESPONSE_CODE, PI_WARN, "Unusual error code", EXPFILL }},
1314 { &ei_xmcp_attr_realm_incorrect, { "xmcp.attr.realm.incorrect", PI_PROTOCOL, PI_WARN, "Incorrect Realm", EXPFILL }},
1315 { &ei_xmcp_attr_length_bad, { "xmcp.attr.length.bad", PI_PROTOCOL, PI_WARN, "Malformed IPv4 address", EXPFILL }},
1316 { &ei_xmcp_xmcp_attr_servtrans_unknown, { "xmcp.attr.service.transport.unknown", PI_PROTOCOL, PI_WARN, "Unknown transport type", EXPFILL }},
1317 { &ei_xmcp_attr_type_unknown, { "xmcp.attr.type.unknown", PI_PROTOCOL, PI_NOTE, "Unrecognized attribute type", EXPFILL }},
1318 { &ei_xmcp_type_reserved_not_zero, { "xmcp.type.reserved.not_zero", PI_PROTOCOL, PI_WARN, "First two bits not zero", EXPFILL }},
1319 { &ei_xmcp_message_class_reserved, { "xmcp.message_class.reserved", PI_PROTOCOL, PI_WARN, "Reserved message class", EXPFILL }},
1320 { &ei_xmcp_error_response, { "xmcp.error_response", PI_RESPONSE_CODE, PI_NOTE, "Error Response", EXPFILL }},
1321 { &ei_xmcp_msg_type_method_reserved, { "xmcp.msg_type_method.reserved", PI_PROTOCOL, PI_WARN, "Reserved message method", EXPFILL }},
1322 { &ei_xmcp_length_bad, { "xmcp.length.bad", PI_PROTOCOL, PI_ERROR, "XMCP message length exceeds packet length", EXPFILL }},
1323 { &ei_xmcp_magic_cookie_incorrect, { "xmcp.cookie.incorrect", PI_PROTOCOL, PI_WARN, "Magic cookie not correct for XMCP", EXPFILL }},
1324 { &ei_xmcp_response_without_request, { "xmcp.response_without_request", PI_SEQUENCE, PI_NOTE, "Response without corresponding request", EXPFILL }},
1325 { &ei_xmcp_new_session, { "xmcp.new_session", PI_SEQUENCE, PI_CHAT, "New session - Register", EXPFILL }},
1326 { &ei_xmcp_session_termination, { "xmcp.session_termination", PI_SEQUENCE, PI_CHAT, "Session termination", EXPFILL }},
1329 expert_module_t* expert_xmcp;
1331 proto_xmcp = proto_register_protocol("eXtensible Messaging Client Protocol", "XMCP", "xmcp");
1333 proto_register_field_array(proto_xmcp, hf, array_length(hf));
1334 proto_register_subtree_array(ett, array_length(ett));
1335 expert_xmcp = expert_register_protocol(proto_xmcp);
1336 expert_register_field_array(expert_xmcp, ei, array_length(ei));
1337 xmcp_tcp_handle = register_dissector("xmcp", dissect_xmcp_tcp, proto_xmcp);
1340 void
1341 proto_reg_handoff_xmcp(void)
1343 heur_dissector_add("tcp", dissect_xmcp_heur, "XMCP over TCP", "xmcp_tcp", proto_xmcp, HEURISTIC_ENABLE);
1344 media_type_dissector_table = find_dissector_table("media_type");
1346 dissector_add_uint_with_preference("tcp.port", TCP_PORT_XMCP, xmcp_tcp_handle);
1350 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1352 * Local variables:
1353 * c-basic-offset: 2
1354 * tab-width: 8
1355 * indent-tabs-mode: nil
1356 * End:
1358 * vi: set shiftwidth=2 tabstop=8 expandtab:
1359 * :indentSize=2:tabSize=8:noTabs=true: