2 * Routines for eXtensible Messaging Client Protocol (XMCP) dissection
3 * Copyright 2011, Glenn Matthews <glenn.matthews@cisco.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * Copied from packet-stun.c
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 * XMCP is a proprietary Cisco protocol based very loosely on the
29 * Session Traversal Utilities for NAT (STUN) protocol.
30 * This dissector is capable of understanding XMCP versions 1.0 and 2.0.
37 #include <epan/packet.h>
38 #include <epan/ipproto.h>
39 #include <epan/addr_resolv.h>
40 #include <packet-tcp.h>
41 #include <epan/prefs.h>
42 #include <epan/conversation.h>
43 #include <epan/wmem/wmem.h>
44 #include <epan/expert.h>
46 static dissector_table_t media_type_dissector_table
;
48 /* Initialize the protocol and registered fields */
49 static int proto_xmcp
= -1;
51 static int hf_xmcp_response_in
= -1;
52 static int hf_xmcp_response_to
= -1;
53 static int hf_xmcp_time
= -1;
55 typedef struct _xmcp_transaction_t
{
56 guint32 request_frame
;
57 guint32 response_frame
;
58 nstime_t request_time
;
59 gboolean request_is_keepalive
;
62 typedef struct _xmcp_conv_info_t
{
63 wmem_tree_t
*transaction_pdus
;
66 static int hf_xmcp_type
= -1;
67 static int hf_xmcp_type_reserved
= -1;
68 static int hf_xmcp_type_class
= -1;
69 static int hf_xmcp_type_method
= -1;
70 static int hf_xmcp_length
= -1;
71 static int hf_xmcp_cookie
= -1;
72 static int hf_xmcp_id
= -1;
73 static int hf_xmcp_attributes
= -1;
74 static int hf_xmcp_attr
= -1;
75 static int hf_xmcp_msg_is_keepalive
= -1;
77 static int xmcp_attr_type
= -1;
78 static int xmcp_attr_length
= -1;
79 static int xmcp_attr_value
= -1; /* generic value for unrecognized attrs */
80 static int xmcp_attr_padding
= -1; /* generic value for TLV padding bytes */
81 static int xmcp_attr_reserved
= -1;
82 static int xmcp_attr_username
= -1;
83 static int xmcp_attr_message_integrity
= -1;
84 static int xmcp_attr_error_reserved
= -1;
85 static int xmcp_attr_error_class
= -1;
86 static int xmcp_attr_error_number
= -1;
87 static int xmcp_attr_error_code
= -1;
88 static int xmcp_attr_error_reason
= -1;
89 static int xmcp_attr_realm
= -1;
90 static int xmcp_attr_nonce
= -1;
91 static int xmcp_attr_client_name
= -1;
92 static int xmcp_attr_client_handle
= -1;
93 static int xmcp_attr_version_major
= -1;
94 static int xmcp_attr_version_minor
= -1;
95 static int xmcp_attr_page_size
= -1;
96 static int xmcp_attr_client_label
= -1;
97 static int xmcp_attr_keepalive
= -1;
98 static int xmcp_attr_serv_service
= -1;
99 static int xmcp_attr_serv_subservice
= -1;
100 static int xmcp_attr_serv_instance
= -1;
101 static int xmcp_attr_servtrans_family
= -1;
102 static int xmcp_attr_servtrans_port
= -1;
103 static int xmcp_attr_servtrans_ipv4
= -1;
104 static int xmcp_attr_servtrans_ipv6
= -1;
105 static int xmcp_attr_service_protocol
= -1;
106 static int xmcp_attr_flag
= -1;
107 static int xmcp_attr_flag_type
= -1;
108 static int xmcp_attr_flag_value
= -1;
109 static int xmcp_attr_flag_removal_reason_network_withdraw
= -1;
110 static int xmcp_attr_flag_removal_reason_reserved
= -1;
111 static int xmcp_attr_flag_trust
= -1;
112 static int xmcp_attr_flag_visibility_unauthenticated
= -1;
113 static int xmcp_attr_flag_visibility_reserved
= -1;
114 static int xmcp_attr_service_version
= -1;
115 static int xmcp_attr_service_data
= -1;
116 static int xmcp_attr_subscription_id
= -1;
117 static int xmcp_attr_service_removed_reason
= -1;
118 static int xmcp_attr_domain
= -1;
120 static gint ett_xmcp
= -1;
121 static gint ett_xmcp_type
= -1;
122 static gint ett_xmcp_attr_all
= -1;
123 static gint ett_xmcp_attr
= -1;
124 static gint ett_xmcp_attr_flag
= -1;
126 static expert_field ei_xmcp_message_class_reserved
= EI_INIT
;
127 static expert_field ei_xmcp_attr_length_bad
= EI_INIT
;
128 static expert_field ei_xmcp_attr_error_number_out_of_range
= EI_INIT
;
129 static expert_field ei_xmcp_type_reserved_not_zero
= EI_INIT
;
130 static expert_field ei_xmcp_data_following_message_integrity
= EI_INIT
;
131 static expert_field ei_xmcp_msg_type_method_reserved
= EI_INIT
;
132 static expert_field ei_xmcp_xmcp_attr_servtrans_unknown
= EI_INIT
;
133 static expert_field ei_xmcp_attr_realm_incorrect
= EI_INIT
;
134 static expert_field ei_xmcp_new_session
= EI_INIT
;
135 static expert_field ei_xmcp_response_without_request
= EI_INIT
;
136 static expert_field ei_xmcp_length_bad
= EI_INIT
;
137 static expert_field ei_xmcp_error_response
= EI_INIT
;
138 static expert_field ei_xmcp_magic_cookie_incorrect
= EI_INIT
;
139 static expert_field ei_xmcp_attr_type_unknown
= EI_INIT
;
140 static expert_field ei_xmcp_session_termination
= EI_INIT
;
141 static expert_field ei_xmcp_attr_error_code_unusual
= EI_INIT
;
143 #define TCP_PORT_XMCP 4788
144 #define XMCP_MAGIC_COOKIE 0x7f5a9bc7
146 void proto_reg_handoff_xmcp(void);
147 static guint global_xmcp_tcp_port
= TCP_PORT_XMCP
;
149 #define XMCP_HDR_LEN 20
150 #define XMCP_ATTR_HDR_LEN 4
152 #define XMCP_TYPE_RESERVED 0xc000
153 #define XMCP_TYPE_CLASS 0x0110
154 #define XMCP_TYPE_METHOD 0x3eef
156 static const int *xmcp_type_fields
[] = {
157 &hf_xmcp_type_reserved
,
158 &hf_xmcp_type_method
,
163 #define XMCP_CLASS_REQUEST 0x00
164 #define XMCP_CLASS_RESERVED 0x01
165 #define XMCP_CLASS_RESPONSE_SUCCESS 0x10
166 #define XMCP_CLASS_RESPONSE_ERROR 0x11
168 static const value_string classes
[] = {
169 {XMCP_CLASS_REQUEST
, "Request"},
170 {XMCP_CLASS_RESERVED
, "RESERVED-CLASS"},
171 {XMCP_CLASS_RESPONSE_SUCCESS
, "Success Response"},
172 {XMCP_CLASS_RESPONSE_ERROR
, "Error Response"},
176 #define XMCP_METHOD_ILLEGAL 0x000
177 #define XMCP_METHOD_REGISTER 0x001
178 #define XMCP_METHOD_UNREGISTER 0x002
179 #define XMCP_METHOD_REG_REVOKE 0x003
180 #define XMCP_METHOD_PUBLISH 0x004
181 #define XMCP_METHOD_UNPUBLISH 0x005
182 #define XMCP_METHOD_PUB_REVOKE 0x006
183 #define XMCP_METHOD_SUBSCRIBE 0x007
184 #define XMCP_METHOD_UNSUBSCRIBE 0x008
185 #define XMCP_METHOD_WITHDRAW 0x009
186 #define XMCP_METHOD_NOTIFY 0x00a
187 #define XMCP_METHOD_KEEPALIVE 0x00b
189 static const value_string methods
[] = {
190 {XMCP_METHOD_ILLEGAL
, "Illegal"},
191 {XMCP_METHOD_REGISTER
, "Register"},
192 {XMCP_METHOD_UNREGISTER
, "Unregister"},
193 {XMCP_METHOD_REG_REVOKE
, "RegisterRevoke"},
194 {XMCP_METHOD_PUBLISH
, "Publish"},
195 {XMCP_METHOD_UNPUBLISH
, "Unpublish"},
196 {XMCP_METHOD_PUB_REVOKE
, "PublishRevoke"},
197 {XMCP_METHOD_SUBSCRIBE
, "Subscribe"},
198 {XMCP_METHOD_UNSUBSCRIBE
, "Unsubscribe"},
199 {XMCP_METHOD_WITHDRAW
, "Withdraw"},
200 {XMCP_METHOD_NOTIFY
, "Notify"},
201 {XMCP_METHOD_KEEPALIVE
, "Keepalive"},
205 #define XMCP_USERNAME 0x0006
206 #define XMCP_MESSAGE_INTEGRITY 0x0008
207 #define XMCP_ERROR_CODE 0x0009
208 #define XMCP_REALM 0x0014
209 #define XMCP_NONCE 0x0015
210 #define XMCP_CLIENT_NAME 0x1001
211 #define XMCP_CLIENT_HANDLE 0x1002
212 #define XMCP_PROTOCOL_VERSION 0x1003
213 #define XMCP_PAGE_SIZE 0x1004
214 #define XMCP_CLIENT_LABEL 0x1005
215 #define XMCP_KEEPALIVE 0x1006
216 #define XMCP_SERVICE_IDENTITY 0x1007
217 #define XMCP_SERVICE_TRANSPORT 0x1008
218 #define XMCP_SERVICE_PROTOCOL 0x1009
219 #define XMCP_FLAGS 0x100a
220 #define XMCP_SERVICE_VERSION 0x100b
221 #define XMCP_SERVICE_DATA 0x100c
222 #define XMCP_SUBSCRIPTION_ID 0x100e
223 #define XMCP_SERVICE_REMOVED_REASON 0x100f
224 #define XMCP_DOMAIN 0x1011
226 static const value_string attributes
[] = {
227 /* Attributes inherited from STUN */
228 {XMCP_USERNAME
, "Username"},
229 {XMCP_MESSAGE_INTEGRITY
, "Message-Integrity"},
230 {XMCP_ERROR_CODE
, "Error-Code"},
231 {XMCP_REALM
, "Realm"},
232 {XMCP_NONCE
, "Nonce"},
233 /* Attributes specific to XMCP */
234 {XMCP_CLIENT_NAME
, "Client-Name"},
235 {XMCP_CLIENT_HANDLE
, "Client-Handle"},
236 {XMCP_PROTOCOL_VERSION
, "Protocol-Version"},
237 {XMCP_PAGE_SIZE
, "PageSize"},
238 {XMCP_CLIENT_LABEL
, "ClientLabel"},
239 {XMCP_KEEPALIVE
, "Keepalive"},
240 {XMCP_SERVICE_IDENTITY
, "ServiceIdentity"},
241 {XMCP_SERVICE_TRANSPORT
, "ServiceTransportAddr"},
242 {XMCP_SERVICE_PROTOCOL
, "ServiceProtocol"},
243 {XMCP_FLAGS
, "Flags"},
244 {XMCP_SERVICE_VERSION
, "ServiceVersion"},
245 {XMCP_SERVICE_DATA
, "ServiceData"},
246 {XMCP_SUBSCRIPTION_ID
, "SubscriptionID"},
247 {XMCP_SERVICE_REMOVED_REASON
, "ServiceRemovedReason"},
248 {XMCP_DOMAIN
, "Domain"},
252 static const value_string error_codes
[] = {
253 {400, "Bad Request"},
254 {401, "Unauthorized"},
255 {413, "Request Too Large"},
256 {431, "Integrity Check Failure"},
257 {435, "Nonce Required"},
258 {436, "Unknown Username"},
259 {438, "Stale Nonce"},
260 {471, "Bad Client Handle"},
261 {472, "Version Number Too Low"},
262 {473, "Unknown Service"},
263 {474, "Unregistered"},
264 {475, "Invalid ServiceIdentity"},
265 {476, "Unknown Subscription"},
266 {477, "Already Registered"},
267 {478, "Unsupported Protocol Version"},
268 {479, "Unknown or Forbidden Domain"},
269 {499, "Miscellaneous Request Error"},
270 {500, "Responder Error"},
271 {501, "Not Implemented"},
275 static const value_string address_families
[] = {
281 #define XMCP_FLAG_REMOVAL_REASON 0x0001
282 #define XMCP_FLAG_TRUST 0x0002
283 #define XMCP_FLAG_SERVICE_VISIBILITY 0x0003
285 static const value_string flag_types
[] = {
286 {XMCP_FLAG_REMOVAL_REASON
, "Removal Reason"},
287 {XMCP_FLAG_TRUST
, "Trust"},
288 {XMCP_FLAG_SERVICE_VISIBILITY
, "Service Visibility"},
292 /* Values for specific flag types */
293 #define XMCP_REMOVAL_REASON_NETWORK_WITHDRAW 0x0001
294 #define XMCP_REMOVAL_REASON_RESERVED 0xfffe
296 #define XMCP_TRUST_LOCAL 0
297 #define XMCP_TRUST_LEARNED 1
299 static const value_string flag_trust_values
[] = {
300 {XMCP_TRUST_LOCAL
, "Local"},
301 {XMCP_TRUST_LEARNED
, "Learned"},
305 #define XMCP_SERVICE_VISIBILITY_UNAUTHENTICATED 0x0001
306 #define XMCP_SERVICE_VISIBILITY_RESERVED 0xfffe
308 static const value_string service_removed_reasons
[] = {
309 {0, "Network withdraw"},
310 {1, "Source withdraw"},
314 /* Dissector state variables */
315 static guint16 xmcp_msg_type_method
= XMCP_METHOD_ILLEGAL
;
316 static guint16 xmcp_msg_type_class
= XMCP_CLASS_RESERVED
;
317 static gboolean xmcp_msg_is_keepalive
= FALSE
;
318 static gint16 xmcp_service_protocol
= -1;
319 static gint32 xmcp_service_port
= -1;
320 static proto_item
*xmcp_it_service_port
= NULL
;
323 get_xmcp_message_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
)
325 return(XMCP_HDR_LEN
+ tvb_get_ntohs(tvb
, offset
+2));
329 get_xmcp_attr_padded_len(guint16 attr_length
)
332 * As in STUN, all XMCP attributes report their length in bytes,
333 * but are padded to the next 4-byte multiple.
335 return((attr_length
+ 3) & 0xfffc);
339 get_xmcp_attr_fixed_len(guint16 xmcp_attr
)
342 * For fixed-length attributes, return their length.
343 * For variable-length attributes, return 0.
346 case XMCP_CLIENT_HANDLE
:
347 case XMCP_PROTOCOL_VERSION
:
350 case XMCP_SERVICE_PROTOCOL
:
351 case XMCP_SERVICE_VERSION
:
352 case XMCP_SUBSCRIPTION_ID
:
353 case XMCP_SERVICE_REMOVED_REASON
:
356 case XMCP_SERVICE_IDENTITY
:
364 get_xmcp_attr_min_len(guint16 xmcp_attr
)
369 case XMCP_CLIENT_NAME
:
370 case XMCP_CLIENT_LABEL
:
372 case XMCP_ERROR_CODE
:
374 case XMCP_SERVICE_TRANSPORT
:
375 return(8); /* 4-byte fixed plus an IPv4 address */
376 case XMCP_MESSAGE_INTEGRITY
:
377 return(20); /* HMAC-SHA1 */
379 return(get_xmcp_attr_fixed_len(xmcp_attr
));
384 get_xmcp_attr_max_len(guint16 xmcp_attr
) {
388 case XMCP_SERVICE_TRANSPORT
:
389 return(20); /* 4-byte fixed plus an IPv6 address */
390 case XMCP_MESSAGE_INTEGRITY
:
391 return(32); /* HMAC-SHA-256 */
393 case XMCP_CLIENT_NAME
:
394 case XMCP_CLIENT_LABEL
:
397 fixed_len
= get_xmcp_attr_fixed_len(xmcp_attr
);
398 return(fixed_len
? fixed_len
: 0xffff);
403 add_xmcp_port_name (void)
405 if (!xmcp_it_service_port
|| xmcp_service_port
== -1)
408 switch(xmcp_service_protocol
) {
410 proto_item_append_text(xmcp_it_service_port
, " (TCP: %s)",
411 get_tcp_port(xmcp_service_port
));
414 proto_item_append_text(xmcp_it_service_port
, " (UDP: %s)",
415 get_udp_port(xmcp_service_port
));
418 proto_item_append_text(xmcp_it_service_port
, " (DCCP: %s)",
419 get_dccp_port(xmcp_service_port
));
422 proto_item_append_text(xmcp_it_service_port
, " (SCTP: %s)",
423 get_sctp_port(xmcp_service_port
));
431 decode_xmcp_attr_value (proto_tree
*attr_tree
, guint16 attr_type
,
432 guint16 attr_length
, tvbuff_t
*tvb
, guint16 offset
,
439 proto_tree_add_item(attr_tree
, xmcp_attr_username
, tvb
, offset
,
440 attr_length
, ENC_ASCII
|ENC_NA
);
441 proto_item_append_text(attr_tree
, ": %s",
442 tvb_get_string(wmem_packet_scope(), tvb
, offset
, attr_length
));
444 * Many message methods may include this attribute,
445 * but it's only interesting when Registering at first
447 if (xmcp_msg_type_method
== XMCP_METHOD_REGISTER
) {
448 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", user \"%s\"",
449 tvb_get_string(wmem_packet_scope(), tvb
, offset
, attr_length
));
452 case XMCP_MESSAGE_INTEGRITY
:
453 proto_tree_add_item(attr_tree
, xmcp_attr_message_integrity
, tvb
, offset
,
454 attr_length
, ENC_NA
);
455 /* Message-integrity should be the last attribute in the message */
456 if ((guint
)(offset
+ get_xmcp_attr_padded_len(attr_length
)) < tvb_reported_length(tvb
)) {
457 expert_add_info(pinfo
, attr_tree
, &ei_xmcp_data_following_message_integrity
);
460 case XMCP_ERROR_CODE
:
463 proto_tree_add_item(attr_tree
, xmcp_attr_error_reserved
, tvb
, offset
,
465 proto_tree_add_item(attr_tree
, xmcp_attr_error_class
, tvb
, offset
,
468 guint8 error_class
, error_number
;
470 it
= proto_tree_add_item(attr_tree
, xmcp_attr_error_number
, tvb
,
471 (offset
+3), 1, ENC_BIG_ENDIAN
);
473 error_class
= tvb_get_guint8(tvb
, offset
+2) & 0x07;
474 error_number
= tvb_get_guint8(tvb
, offset
+3);
476 if (error_number
> 99) {
477 expert_add_info(pinfo
, it
, &ei_xmcp_attr_error_number_out_of_range
);
479 /* Error code = error class + (error num % 100) */
480 error_code
= (error_class
* 100) + error_number
;
481 it
= proto_tree_add_uint(attr_tree
, xmcp_attr_error_code
, tvb
,
482 (offset
+2), 2, error_code
);
483 PROTO_ITEM_SET_GENERATED(it
);
484 proto_item_append_text(attr_tree
, ": %d", error_code
);
485 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", error %d (%s)", error_code
,
486 val_to_str_const(error_code
, error_codes
, "Unknown"));
489 * All error responses default to a PI_NOTE severity.
490 * Some specific error codes are more significant, so mark them up.
492 switch (error_code
) {
493 case 400: /* Bad Request */
494 case 431: /* Integrity Check Failure */
495 case 473: /* Unknown Service */
496 case 476: /* Unknown Subscription */
497 case 477: /* Already Registered */
498 case 499: /* Miscellaneous Request Error */
499 case 500: /* Responder Error */
500 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"));
509 proto_tree_add_item(attr_tree
, xmcp_attr_error_reason
, tvb
, (offset
+4),
510 (attr_length
- 4), ENC_ASCII
|ENC_NA
);
511 proto_item_append_text(attr_tree
, " (%s)",
512 tvb_get_string(wmem_packet_scope(), tvb
, (offset
+4),
516 it
= proto_tree_add_item(attr_tree
, xmcp_attr_realm
, tvb
, offset
,
517 attr_length
, ENC_ASCII
|ENC_NA
);
520 realm
= tvb_get_string(wmem_packet_scope(), tvb
, offset
, attr_length
);
521 proto_item_append_text(attr_tree
, ": %s", realm
);
522 /* In XMCP the REALM string should always be "SAF" including the quotes */
523 if (attr_length
!= 5 || strncmp(realm
, "\"SAF\"", attr_length
)) {
524 expert_add_info(pinfo
, it
, &ei_xmcp_attr_realm_incorrect
);
529 proto_tree_add_item(attr_tree
, xmcp_attr_nonce
, tvb
, offset
,
530 attr_length
, ENC_ASCII
|ENC_NA
);
531 proto_item_append_text(attr_tree
, ": %s",
532 tvb_get_string(wmem_packet_scope(), tvb
, offset
, attr_length
));
534 case XMCP_CLIENT_NAME
:
535 proto_tree_add_item(attr_tree
, xmcp_attr_client_name
, tvb
, offset
,
536 attr_length
, ENC_ASCII
|ENC_NA
);
537 proto_item_append_text(attr_tree
, ": %s",
538 tvb_get_string(wmem_packet_scope(), tvb
, offset
, attr_length
));
539 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", name \"%s\"",
540 tvb_get_string(wmem_packet_scope(), tvb
, offset
, attr_length
));
542 case XMCP_CLIENT_HANDLE
:
545 proto_tree_add_item(attr_tree
, xmcp_attr_client_handle
, tvb
, offset
,
547 proto_item_append_text(attr_tree
, ": %u", tvb_get_ntohl(tvb
, offset
));
548 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", handle %u",
549 tvb_get_ntohl(tvb
, offset
));
551 * A Register request containing a Client-Handle is considered
554 if (xmcp_msg_type_method
== XMCP_METHOD_REGISTER
&&
555 xmcp_msg_type_class
== XMCP_CLASS_REQUEST
) {
556 xmcp_msg_is_keepalive
= TRUE
;
559 case XMCP_PROTOCOL_VERSION
:
562 proto_tree_add_item(attr_tree
, xmcp_attr_version_major
, tvb
, offset
,
566 proto_tree_add_item(attr_tree
, xmcp_attr_version_minor
, tvb
, (offset
+2),
568 proto_item_append_text(attr_tree
, ": %u.%u", tvb_get_ntohs(tvb
, offset
),
569 tvb_get_ntohs(tvb
, (offset
+2)));
574 proto_tree_add_item(attr_tree
, xmcp_attr_page_size
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
575 proto_item_append_text(attr_tree
, ": %u", tvb_get_ntohl(tvb
, offset
));
577 case XMCP_CLIENT_LABEL
:
578 proto_tree_add_item(attr_tree
, xmcp_attr_client_label
, tvb
, offset
,
579 attr_length
, ENC_ASCII
|ENC_NA
);
580 proto_item_append_text(attr_tree
, ": %s",
581 tvb_get_string(wmem_packet_scope(), tvb
, offset
, attr_length
));
582 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", label \"%s\"",
583 tvb_get_string(wmem_packet_scope(), tvb
, offset
, attr_length
));
588 proto_tree_add_item(attr_tree
, xmcp_attr_keepalive
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
589 proto_item_append_text(attr_tree
, ": %u", tvb_get_ntohl(tvb
, offset
));
591 case XMCP_SERVICE_IDENTITY
:
594 proto_tree_add_item(attr_tree
, xmcp_attr_serv_service
, tvb
, offset
,
598 proto_tree_add_item(attr_tree
, xmcp_attr_serv_subservice
, tvb
, (offset
+2),
600 if (attr_length
< 20)
602 proto_tree_add_item(attr_tree
, xmcp_attr_serv_instance
, tvb
, (offset
+4),
606 char buf
[GUID_STR_LEN
];
607 tvb_get_guid(tvb
, (offset
+4), &guid
, ENC_BIG_ENDIAN
);
608 guid_to_str_buf(&guid
, buf
, sizeof(buf
));
609 proto_item_append_text(attr_tree
, ": %u:%u:%s",
610 tvb_get_ntohs(tvb
, offset
),
611 tvb_get_ntohs(tvb
, (offset
+2)), buf
);
612 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", service %u:%u:%s",
613 tvb_get_ntohs(tvb
, offset
),
614 tvb_get_ntohs(tvb
, (offset
+2)), buf
);
617 case XMCP_SERVICE_TRANSPORT
:
619 * One byte of padding, one byte indicating family,
620 * two bytes for port, followed by addr
624 proto_tree_add_item(attr_tree
, xmcp_attr_reserved
, tvb
, offset
, 1, ENC_NA
);
627 proto_tree_add_item(attr_tree
, xmcp_attr_servtrans_family
, tvb
,
628 (offset
+1), 1, ENC_BIG_ENDIAN
);
631 xmcp_service_port
= tvb_get_ntohs(tvb
, (offset
+2));
632 xmcp_it_service_port
= proto_tree_add_item(attr_tree
,
633 xmcp_attr_servtrans_port
,
634 tvb
, (offset
+2), 2, ENC_BIG_ENDIAN
);
635 /* If we now know both port and protocol number, fill in the port name */
636 if (xmcp_service_protocol
!= -1) {
637 add_xmcp_port_name();
639 switch (tvb_get_guint8(tvb
, (offset
+1))) {
640 case 0x01: /* IPv4 */
641 if (attr_length
!= 8) {
642 expert_add_info_format(pinfo
, attr_tree
, &ei_xmcp_attr_length_bad
, "Malformed IPv4 address");
645 proto_tree_add_item(attr_tree
, xmcp_attr_servtrans_ipv4
, tvb
,
646 (offset
+4), 4, ENC_BIG_ENDIAN
);
647 ip
= tvb_get_ipv4(tvb
, (offset
+4));
648 proto_item_append_text(attr_tree
, ": %s:%u", ip_to_str((guint8
*)&ip
),
649 tvb_get_ntohs(tvb
, (offset
+2)));
652 case 0x02: /* IPv6 */
653 if (attr_length
!= 20) {
654 expert_add_info_format(pinfo
, attr_tree
, &ei_xmcp_attr_length_bad
, "Malformed IPv6 address");
656 struct e_in6_addr ipv6
;
657 proto_tree_add_item(attr_tree
, xmcp_attr_servtrans_ipv6
, tvb
,
658 (offset
+4), 16, ENC_NA
);
659 tvb_get_ipv6(tvb
, (offset
+4), &ipv6
);
660 proto_item_append_text(attr_tree
, ": [%s]:%u", ip6_to_str(&ipv6
),
661 tvb_get_ntohs(tvb
, (offset
+2)));
665 expert_add_info(pinfo
, attr_tree
, &ei_xmcp_xmcp_attr_servtrans_unknown
);
669 case XMCP_SERVICE_PROTOCOL
:
670 /* Three bytes of padding followed by a 1-byte protocol number */
673 proto_tree_add_item(attr_tree
, xmcp_attr_reserved
, tvb
, offset
, 3, ENC_NA
);
674 proto_tree_add_item(attr_tree
, xmcp_attr_service_protocol
, tvb
,
675 (offset
+3), 1, ENC_BIG_ENDIAN
);
676 xmcp_service_protocol
= tvb_get_guint8(tvb
, (offset
+3));
677 proto_item_append_text(attr_tree
, ": %u (%s)", xmcp_service_protocol
,
678 val_to_str_ext_const(xmcp_service_protocol
,
679 &ipproto_val_ext
, "Unknown"));
680 /* If we now know both port and protocol number, fill in the port name */
681 if (xmcp_service_port
!= -1 && xmcp_it_service_port
!= NULL
) {
682 add_xmcp_port_name();
686 /* Flags is a series of type-value pairs */
687 if (attr_length
% 4 != 0) {
688 expert_add_info_format(pinfo
, attr_tree
, &ei_xmcp_attr_length_bad
, "Malformed Flags - length not divisible by 4");
691 guint16 flag_type
, flag_value
, current_offset
= offset
;
693 proto_tree
*flag_tree
;
694 while ((current_offset
-offset
)+3 < attr_length
) {
695 flag_type
= tvb_get_ntohs(tvb
, (current_offset
));
696 flag_value
= tvb_get_ntohs(tvb
, (current_offset
+2));
697 ti
= proto_tree_add_none_format(attr_tree
, xmcp_attr_flag
, tvb
,
700 val_to_str_const(flag_type
, flag_types
,
702 flag_tree
= proto_item_add_subtree(ti
, ett_xmcp_attr_flag
);
703 proto_tree_add_item(flag_tree
, xmcp_attr_flag_type
, tvb
,
704 current_offset
, 2, ENC_BIG_ENDIAN
);
708 case XMCP_FLAG_REMOVAL_REASON
:
709 proto_tree_add_item(flag_tree
, xmcp_attr_flag_removal_reason_reserved
,
710 tvb
, current_offset
, 2, ENC_BIG_ENDIAN
);
711 proto_tree_add_item(flag_tree
,
712 xmcp_attr_flag_removal_reason_network_withdraw
,
713 tvb
, current_offset
, 2, ENC_BIG_ENDIAN
);
714 if (flag_value
& XMCP_REMOVAL_REASON_NETWORK_WITHDRAW
) {
715 proto_item_append_text(flag_tree
, " (network withdraw)");
718 proto_item_append_text(flag_tree
, " (source withdraw)");
721 case XMCP_FLAG_TRUST
:
722 proto_tree_add_item(flag_tree
, xmcp_attr_flag_trust
, tvb
,
723 current_offset
, 2, ENC_BIG_ENDIAN
);
724 proto_item_append_text(flag_tree
, " %s",
725 val_to_str_const(flag_value
, flag_trust_values
,
728 case XMCP_FLAG_SERVICE_VISIBILITY
:
729 proto_tree_add_item(flag_tree
, xmcp_attr_flag_visibility_reserved
,
730 tvb
, current_offset
, 2, ENC_BIG_ENDIAN
);
731 proto_tree_add_item(flag_tree
,
732 xmcp_attr_flag_visibility_unauthenticated
,
733 tvb
, current_offset
, 2, ENC_BIG_ENDIAN
);
734 if (flag_value
& XMCP_SERVICE_VISIBILITY_UNAUTHENTICATED
) {
735 proto_item_append_text(flag_tree
,
736 " (visible to unauthenticated clients)");
739 proto_item_append_text(flag_tree
, " (default)");
743 proto_tree_add_item(flag_tree
, xmcp_attr_flag_value
, tvb
,
744 current_offset
, 2, ENC_BIG_ENDIAN
);
745 proto_item_append_text(flag_tree
, " 0x%04x", flag_value
);
752 case XMCP_SERVICE_VERSION
:
755 proto_tree_add_item(attr_tree
, xmcp_attr_service_version
, tvb
, offset
,
757 proto_item_append_text(attr_tree
, ": %u", tvb_get_ntohl(tvb
, offset
));
759 case XMCP_SERVICE_DATA
:
760 proto_tree_add_item(attr_tree
, xmcp_attr_service_data
, tvb
, offset
,
761 attr_length
, ENC_NA
);
762 if (attr_length
> 0) {
764 guint8
*test_string
, *tok
;
766 next_tvb
= tvb_new_subset(tvb
, offset
, attr_length
, attr_length
);
768 * Service-Data is usually (but not always) plain text, specifically XML.
769 * If it "looks like" XML (begins with optional whitespace followed by
771 * Otherwise, try plain-text.
773 test_string
= tvb_get_string(wmem_packet_scope(), next_tvb
, 0, (attr_length
< 32 ?
775 tok
= strtok(test_string
, " \t\r\n");
776 if (tok
&& tok
[0] == '<') {
778 dissector_try_string(media_type_dissector_table
, "application/xml",
779 next_tvb
, pinfo
, attr_tree
, NULL
);
782 dissector_try_string(media_type_dissector_table
, "text/plain",
783 next_tvb
, pinfo
, attr_tree
, NULL
);
787 case XMCP_SUBSCRIPTION_ID
:
790 proto_tree_add_item(attr_tree
, xmcp_attr_subscription_id
, tvb
, offset
,
792 proto_item_append_text(attr_tree
, ": %u", tvb_get_ntohl(tvb
, offset
));
793 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", subscription %u",
794 tvb_get_ntohl(tvb
, offset
));
796 case XMCP_SERVICE_REMOVED_REASON
:
799 proto_tree_add_item(attr_tree
, xmcp_attr_service_removed_reason
, tvb
,
800 offset
, 4, ENC_BIG_ENDIAN
);
801 proto_item_append_text(attr_tree
, ": %s",
802 val_to_str_const(tvb_get_ntohl(tvb
, offset
),
803 service_removed_reasons
,
809 proto_tree_add_item(attr_tree
, xmcp_attr_domain
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
810 proto_item_append_text(attr_tree
, ": %u", tvb_get_ntohl(tvb
, offset
));
813 proto_tree_add_item(attr_tree
, xmcp_attr_value
, tvb
, offset
,
814 attr_length
, ENC_NA
);
815 expert_add_info(pinfo
, attr_tree
, &ei_xmcp_attr_type_unknown
);
818 if (attr_length
% 4 != 0) {
819 proto_tree_add_item(attr_tree
, xmcp_attr_padding
, tvb
, (offset
+attr_length
),
820 (4 - (attr_length
% 4)), ENC_NA
);
822 if (attr_length
< get_xmcp_attr_min_len(attr_type
)) {
823 expert_add_info_format(pinfo
, attr_tree
, &ei_xmcp_attr_length_bad
, "Length less than minimum for this attribute type");
824 } else if (attr_length
> get_xmcp_attr_max_len(attr_type
)) {
825 expert_add_info_format(pinfo
, attr_tree
, &ei_xmcp_attr_length_bad
, "Length exceeds maximum for this attribute type");
830 dissect_xmcp_message(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
832 guint16 msg_type
, msg_length
;
833 proto_item
*ti
= NULL
;
834 proto_tree
*xmcp_tree
, *attr_all_tree
, *attr_tree
;
835 guint16 offset
, attr_type
, attr_length
;
837 /* For request/response association */
838 guint32 transaction_id
[3];
839 wmem_tree_key_t transaction_id_key
[2];
840 conversation_t
*conversation
;
841 xmcp_conv_info_t
*xmcp_conv_info
;
842 xmcp_transaction_t
*xmcp_trans
;
844 if (tvb_reported_length(tvb
) < XMCP_HDR_LEN
) {
847 /* Check for valid message type field */
848 msg_type
= tvb_get_ntohs(tvb
, 0);
849 if (msg_type
& XMCP_TYPE_RESERVED
) { /* First 2 bits must be 0 */
852 /* Check for valid "magic cookie" field */
853 if (tvb_get_ntohl(tvb
, 4) != XMCP_MAGIC_COOKIE
) {
857 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "XMCP");
858 /* Clear out stuff in the info column */
859 col_clear(pinfo
->cinfo
, COL_INFO
);
861 /* As in STUN, the first 2 bytes contain the message class and method */
862 xmcp_msg_type_class
= ((msg_type
& XMCP_TYPE_CLASS
) >> 4);
863 xmcp_msg_type_method
= (msg_type
& XMCP_TYPE_METHOD
);
864 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s %s",
865 val_to_str_const(xmcp_msg_type_method
, methods
, "Unknown"),
866 val_to_str_const(xmcp_msg_type_class
, classes
, "Unknown"));
868 /* Get the transaction ID */
869 transaction_id
[0] = tvb_get_ntohl(tvb
, 8);
870 transaction_id
[1] = tvb_get_ntohl(tvb
, 12);
871 transaction_id
[2] = tvb_get_ntohl(tvb
, 16);
873 transaction_id_key
[0].length
= 3;
874 transaction_id_key
[0].key
= transaction_id
;
875 transaction_id_key
[1].length
= 0;
876 transaction_id_key
[1].key
= NULL
;
878 conversation
= find_or_create_conversation(pinfo
);
880 /* Do we already have XMCP state for this conversation? */
881 xmcp_conv_info
= (xmcp_conv_info_t
*)conversation_get_proto_data(conversation
, proto_xmcp
);
882 if (!xmcp_conv_info
) {
883 xmcp_conv_info
= wmem_new(wmem_file_scope(), xmcp_conv_info_t
);
884 xmcp_conv_info
->transaction_pdus
= wmem_tree_new(wmem_file_scope());
885 conversation_add_proto_data(conversation
, proto_xmcp
, xmcp_conv_info
);
888 /* Find existing transaction entry or create a new one */
889 xmcp_trans
= (xmcp_transaction_t
*)wmem_tree_lookup32_array(xmcp_conv_info
->transaction_pdus
,
892 xmcp_trans
= wmem_new(wmem_file_scope(), xmcp_transaction_t
);
893 xmcp_trans
->request_frame
= 0;
894 xmcp_trans
->response_frame
= 0;
895 xmcp_trans
->request_time
= pinfo
->fd
->abs_ts
;
896 xmcp_trans
->request_is_keepalive
= FALSE
;
897 wmem_tree_insert32_array(xmcp_conv_info
->transaction_pdus
,
898 transaction_id_key
, (void *)xmcp_trans
);
901 /* Update transaction entry */
902 if (!pinfo
->fd
->flags
.visited
) {
903 if (xmcp_msg_type_class
== XMCP_CLASS_REQUEST
) {
904 if (xmcp_trans
->request_frame
== 0) {
905 xmcp_trans
->request_frame
= pinfo
->fd
->num
;
906 xmcp_trans
->request_time
= pinfo
->fd
->abs_ts
;
908 } else if (xmcp_msg_type_class
!= XMCP_CLASS_RESERVED
) {
909 if (xmcp_trans
->response_frame
== 0) {
910 xmcp_trans
->response_frame
= pinfo
->fd
->num
;
915 ti
= proto_tree_add_item(tree
, proto_xmcp
, tvb
, 0, -1, ENC_NA
);
916 xmcp_tree
= proto_item_add_subtree(ti
, ett_xmcp
);
918 ti
= proto_tree_add_bitmask(xmcp_tree
, tvb
, 0, hf_xmcp_type
, ett_xmcp_type
,
919 xmcp_type_fields
, ENC_BIG_ENDIAN
);
921 if (msg_type
& XMCP_TYPE_RESERVED
) {
922 expert_add_info(pinfo
, ti
, &ei_xmcp_type_reserved_not_zero
);
924 if (xmcp_msg_type_class
== XMCP_CLASS_RESERVED
) {
925 expert_add_info(pinfo
, ti
, &ei_xmcp_message_class_reserved
);
926 } else if (xmcp_msg_type_class
== XMCP_CLASS_RESPONSE_ERROR
) {
927 expert_add_info(pinfo
, ti
, &ei_xmcp_error_response
);
930 if (xmcp_msg_type_method
< 0x001 || xmcp_msg_type_method
> 0x00b) {
931 expert_add_info(pinfo
, ti
, &ei_xmcp_msg_type_method_reserved
);
935 * Some forms of XMCP overload the Register method for Keepalive packets
936 * rather than using a separate Keepalive method. We'll try to determine from
937 * the message contents whether this message is a Keepalive. Initialize first.
939 xmcp_msg_is_keepalive
= (xmcp_trans
->request_is_keepalive
||
940 (xmcp_msg_type_method
== XMCP_METHOD_KEEPALIVE
));
942 /* After the class/method, we have a 2 byte length...*/
943 ti
= proto_tree_add_item(xmcp_tree
, hf_xmcp_length
, tvb
, 2, 2, ENC_BIG_ENDIAN
);
944 msg_length
= tvb_get_ntohs(tvb
, 2);
945 if ((guint
)(msg_length
+ XMCP_HDR_LEN
) > tvb_reported_length(tvb
)) {
946 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
));
947 return tvb_length(tvb
);
950 /* ...a 4 byte magic cookie... */
951 ti
= proto_tree_add_item(xmcp_tree
, hf_xmcp_cookie
, tvb
, 4, 4, ENC_BIG_ENDIAN
);
952 if (tvb_get_ntohl(tvb
, 4) != XMCP_MAGIC_COOKIE
) {
953 expert_add_info(pinfo
, ti
, &ei_xmcp_magic_cookie_incorrect
);
956 /* ...and a 12-byte transaction id */
957 ti
= proto_tree_add_item(xmcp_tree
, hf_xmcp_id
, tvb
, 8, 12, ENC_NA
);
959 /* Print state tracking in the tree */
960 if (xmcp_msg_type_class
== XMCP_CLASS_REQUEST
) {
961 if (xmcp_trans
->response_frame
) {
962 ti
= proto_tree_add_uint(xmcp_tree
, hf_xmcp_response_in
, tvb
, 0, 0,
963 xmcp_trans
->response_frame
);
964 PROTO_ITEM_SET_GENERATED(ti
);
966 } else if (xmcp_msg_type_class
!= XMCP_CLASS_RESERVED
) {
967 if (xmcp_trans
->request_frame
) {
970 ti
= proto_tree_add_uint(xmcp_tree
, hf_xmcp_response_to
, tvb
, 0, 0,
971 xmcp_trans
->request_frame
);
972 PROTO_ITEM_SET_GENERATED(ti
);
974 nstime_delta(&ns
, &pinfo
->fd
->abs_ts
, &xmcp_trans
->request_time
);
975 ti
= proto_tree_add_time(xmcp_tree
, hf_xmcp_time
, tvb
, 0, 0, &ns
);
976 PROTO_ITEM_SET_GENERATED(ti
);
978 /* This is a response, but we don't know about a request for this response? */
979 expert_add_info(pinfo
, ti
, &ei_xmcp_response_without_request
);
983 xmcp_service_protocol
= -1;
984 xmcp_service_port
= -1;
985 xmcp_it_service_port
= NULL
;
987 /* The header is then followed by "msg_length" bytes of TLV attributes */
988 if (msg_length
> 0) {
989 ti
= proto_tree_add_item(xmcp_tree
, hf_xmcp_attributes
, tvb
,
990 XMCP_HDR_LEN
, msg_length
, ENC_NA
);
991 attr_all_tree
= proto_item_add_subtree(ti
, ett_xmcp_attr_all
);
993 offset
= XMCP_HDR_LEN
;
995 while (offset
< (msg_length
+ XMCP_HDR_LEN
)) {
996 /* Get type/length of next TLV */
997 attr_type
= tvb_get_ntohs(tvb
, offset
);
998 attr_length
= tvb_get_ntohs(tvb
, offset
+2);
999 ti
= proto_tree_add_none_format(attr_all_tree
, hf_xmcp_attr
, tvb
, offset
,
1000 (XMCP_ATTR_HDR_LEN
+
1001 get_xmcp_attr_padded_len(attr_length
)),
1003 val_to_str_const(attr_type
, attributes
,
1007 /* Add subtree for this TLV */
1008 attr_tree
= proto_item_add_subtree(ti
, ett_xmcp_attr
);
1010 proto_tree_add_item(attr_tree
, xmcp_attr_type
, tvb
,
1011 offset
, 2, ENC_BIG_ENDIAN
);
1013 ti
= proto_tree_add_item(attr_tree
, xmcp_attr_length
, tvb
,
1014 offset
, 2, ENC_BIG_ENDIAN
);
1017 if ((offset
+ attr_length
) > (XMCP_HDR_LEN
+ msg_length
)) {
1018 proto_item_append_text(ti
, " (bogus, exceeds message length)");
1019 expert_add_info_format(pinfo
, attr_tree
, &ei_xmcp_attr_length_bad
, "Attribute length exceeds message length");
1023 decode_xmcp_attr_value(attr_tree
, attr_type
, attr_length
, tvb
,
1026 offset
+= get_xmcp_attr_padded_len(attr_length
);
1031 * Flag this message as a keepalive if the attribute analysis
1032 * suggested that it is one
1034 if (xmcp_msg_is_keepalive
) {
1035 ti
= proto_tree_add_none_format(xmcp_tree
, hf_xmcp_msg_is_keepalive
, tvb
,
1036 0, 0, "This is a Keepalive message");
1037 PROTO_ITEM_SET_GENERATED(ti
);
1038 if (xmcp_msg_type_method
!= XMCP_METHOD_KEEPALIVE
) {
1039 col_prepend_fstr(pinfo
->cinfo
, COL_INFO
, "[Keepalive] ");
1041 if (xmcp_msg_type_class
== XMCP_CLASS_REQUEST
) {
1042 xmcp_trans
->request_is_keepalive
= TRUE
;
1044 } else if (xmcp_msg_type_class
== XMCP_CLASS_REQUEST
||
1045 xmcp_msg_type_class
== XMCP_CLASS_RESPONSE_SUCCESS
) {
1046 if (xmcp_msg_type_method
== XMCP_METHOD_REGISTER
) {
1047 expert_add_info_format(pinfo
, xmcp_tree
, &ei_xmcp_new_session
, "New session - Register %s", val_to_str_const(xmcp_msg_type_class
, classes
, ""));
1048 } else if (xmcp_msg_type_method
== XMCP_METHOD_UNREGISTER
||
1049 xmcp_msg_type_method
== XMCP_METHOD_REG_REVOKE
) {
1050 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
, ""));
1054 return tvb_length(tvb
);
1058 dissect_xmcp_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
1060 tcp_dissect_pdus(tvb
, pinfo
, tree
, TRUE
, XMCP_HDR_LEN
,
1061 get_xmcp_message_len
, dissect_xmcp_message
, data
);
1062 return tvb_length(tvb
);
1066 dissect_xmcp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
1068 /* See if this looks like a real XMCP packet */
1069 if (tvb_length(tvb
) < XMCP_HDR_LEN
) {
1072 /* Check for valid message type field */
1073 if (tvb_get_ntohs(tvb
, 0) & XMCP_TYPE_RESERVED
) { /* First 2 bits must be 0 */
1076 /* Check for valid "magic cookie" field */
1077 if (tvb_get_ntohl(tvb
, 4) != XMCP_MAGIC_COOKIE
) {
1081 /* Good enough to consider a match! */
1082 tcp_dissect_pdus(tvb
, pinfo
, tree
, TRUE
, XMCP_HDR_LEN
,
1083 get_xmcp_message_len
, dissect_xmcp_message
, data
);
1088 proto_register_xmcp(void)
1090 static hf_register_info hf
[] = {
1092 { "Message Type", "xmcp.type",
1093 FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
}
1095 { &hf_xmcp_type_reserved
,
1096 { "Reserved", "xmcp.type.reserved",
1097 FT_UINT16
, BASE_HEX
, NULL
, XMCP_TYPE_RESERVED
, NULL
, HFILL
}
1099 { &hf_xmcp_type_class
,
1100 { "Class", "xmcp.type.class",
1101 FT_UINT16
, BASE_HEX
, VALS(classes
), XMCP_TYPE_CLASS
, NULL
, HFILL
}
1103 { &hf_xmcp_type_method
,
1104 { "Method", "xmcp.type.method",
1105 FT_UINT16
, BASE_HEX
, VALS(methods
), XMCP_TYPE_METHOD
, NULL
, HFILL
}
1107 { &hf_xmcp_msg_is_keepalive
,
1108 { "Message is Keepalive", "xmcp.analysis.keepalive",
1109 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1112 { "Message Length", "xmcp.length",
1113 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1116 { "XMCP Magic Cookie", "xmcp.cookie",
1117 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
1120 { "Transaction ID", "xmcp.id",
1121 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1123 { &hf_xmcp_response_in
,
1124 { "Response In", "xmcp.response-in",
1125 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1126 "The response to this XMCP request is in this frame", HFILL
}
1128 { &hf_xmcp_response_to
,
1129 { "Response To", "xmcp.response-to",
1130 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
1131 "This is a response to the XMCP request in this frame", HFILL
}
1134 { "Elapsed Time", "xmcp.time",
1135 FT_RELATIVE_TIME
, BASE_NONE
, NULL
, 0x0,
1136 "The time between the Request and the Response", HFILL
}
1138 { &hf_xmcp_attributes
,
1139 { "Attributes", "xmcp.attributes",
1140 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1143 { "Attribute", "xmcp.attr",
1144 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1147 { "Attribute Type", "xmcp.attr.type",
1148 FT_UINT16
, BASE_HEX
, VALS(attributes
), 0x0, NULL
, HFILL
}
1150 { &xmcp_attr_length
,
1151 { "Attribute Length", "xmcp.attr.length",
1152 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1155 { "Attribute Value", "xmcp.attr.value",
1156 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1158 { &xmcp_attr_padding
,
1159 { "Padding", "xmcp.attr.padding",
1160 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1162 { &xmcp_attr_reserved
,
1163 { "Reserved", "xmcp.attr.reserved",
1164 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1166 { &xmcp_attr_username
,
1167 { "Username", "xmcp.attr.username",
1168 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1170 { &xmcp_attr_message_integrity
,
1171 { "Message-Integrity", "xmcp.attr.hmac",
1172 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1174 { &xmcp_attr_error_reserved
,
1175 { "Reserved", "xmcp.attr.error.reserved",
1176 FT_UINT24
, BASE_HEX
, NULL
, 0xFFFFF8, NULL
, HFILL
}
1178 { &xmcp_attr_error_class
,
1179 { "Error Class", "xmcp.attr.error.class",
1180 FT_UINT24
, BASE_DEC
, NULL
, 0x000007, NULL
, HFILL
}
1182 { &xmcp_attr_error_number
,
1183 { "Error Number", "xmcp.attr.error.number",
1184 FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1186 { &xmcp_attr_error_code
,
1187 { "Error Code", "xmcp.attr.error",
1188 FT_UINT16
, BASE_DEC
, VALS(error_codes
), 0x0, NULL
, HFILL
}
1190 { &xmcp_attr_error_reason
,
1191 { "Error Reason Phrase", "xmcp.attr.error.reason",
1192 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1195 { "Realm", "xmcp.attr.realm",
1196 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1199 { "Nonce", "xmcp.attr.nonce",
1200 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1202 { &xmcp_attr_client_name
,
1203 { "Client-Name", "xmcp.attr.client-name",
1204 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1206 { &xmcp_attr_client_handle
,
1207 { "Client-Handle", "xmcp.attr.client-handle",
1208 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1210 { &xmcp_attr_version_major
,
1211 { "Protocol Major Version", "xmcp.attr.version.major",
1212 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1214 { &xmcp_attr_version_minor
,
1215 { "Protocol Minor Version", "xmcp.attr.version.minor",
1216 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1218 { &xmcp_attr_page_size
,
1219 { "Page-Size", "xmcp.attr.page-size",
1220 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1222 { &xmcp_attr_client_label
,
1223 { "Client-Label", "xmcp.attr.client-label",
1224 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1226 { &xmcp_attr_keepalive
,
1227 { "Keepalive", "xmcp.attr.keepalive",
1228 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1230 { &xmcp_attr_serv_service
,
1231 { "Service ID", "xmcp.attr.service.service",
1232 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1234 { &xmcp_attr_serv_subservice
,
1235 { "Subservice ID", "xmcp.attr.service.subservice",
1236 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1238 { &xmcp_attr_serv_instance
,
1239 { "Instance ID", "xmcp.attr.service.instance",
1240 FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1242 { &xmcp_attr_servtrans_family
,
1243 { "Family", "xmcp.attr.service.transport.family",
1244 FT_UINT8
, BASE_HEX
, VALS(address_families
), 0x0, NULL
, HFILL
}
1246 { &xmcp_attr_servtrans_port
,
1247 { "Port", "xmcp.attr.service.transport.port",
1248 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1250 { &xmcp_attr_servtrans_ipv4
,
1251 { "IPv4 Address", "xmcp.attr.service.transport.ipv4",
1252 FT_IPv4
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1254 { &xmcp_attr_servtrans_ipv6
,
1255 { "IPv6 Address", "xmcp.attr.service.transport.ipv6",
1256 FT_IPv6
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1258 { &xmcp_attr_service_protocol
,
1259 { "Protocol", "xmcp.attr.service.transport.protocol",
1260 FT_UINT8
, BASE_DEC
|BASE_EXT_STRING
, (&ipproto_val_ext
),
1264 { "Flag", "xmcp.attr.flag",
1265 FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1267 { &xmcp_attr_flag_type
,
1268 { "Flag Type", "xmcp.attr.flag.type",
1269 FT_UINT16
, BASE_HEX
, VALS(flag_types
), 0x0, NULL
, HFILL
}
1271 { &xmcp_attr_flag_value
,
1272 { "Flag Value", "xmcp.attr.flag.value",
1273 FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
}
1275 { &xmcp_attr_flag_removal_reason_network_withdraw
,
1276 { "Network Withdraw",
1277 "xmcp.attr.flag.removal-reason.network-withdraw",
1278 FT_BOOLEAN
, 16, TFS(&tfs_true_false
),
1279 XMCP_REMOVAL_REASON_NETWORK_WITHDRAW
, NULL
, HFILL
}
1281 { &xmcp_attr_flag_removal_reason_reserved
,
1282 { "Reserved", "xmcp.attr.flag.removal-reason.reserved",
1283 FT_UINT16
, BASE_HEX
, NULL
, XMCP_REMOVAL_REASON_RESERVED
, NULL
, HFILL
}
1285 { &xmcp_attr_flag_trust
,
1286 { "Trust", "xmcp.attr.flag.trust",
1287 FT_UINT16
, BASE_HEX
, VALS(flag_trust_values
), 0x0, NULL
, HFILL
}
1289 { &xmcp_attr_flag_visibility_unauthenticated
,
1290 { "Visible to Unauthenticated Clients",
1291 "xmcp.attr.flag.service-visibility.unauthenticated",
1292 FT_BOOLEAN
, 16, TFS(&tfs_yes_no
),
1293 XMCP_SERVICE_VISIBILITY_UNAUTHENTICATED
, NULL
, HFILL
}
1295 { &xmcp_attr_flag_visibility_reserved
,
1296 { "Reserved", "xmcp.attr.flag.service-visibility.reserved",
1297 FT_UINT16
, BASE_HEX
, NULL
,
1298 XMCP_SERVICE_VISIBILITY_RESERVED
, NULL
, HFILL
}
1300 { &xmcp_attr_service_version
,
1301 { "Service Version", "xmcp.attr.service.version",
1302 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1304 { &xmcp_attr_service_data
,
1305 { "Service Data", "xmcp.attr.service.data",
1306 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}
1308 { &xmcp_attr_subscription_id
,
1309 { "Subscription ID", "xmcp.attr.subscription-id",
1310 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1312 { &xmcp_attr_service_removed_reason
,
1313 { "Service Removed Reason", "xmcp.attr.service-removed-reason",
1314 FT_UINT32
, BASE_DEC
, VALS(service_removed_reasons
), 0x0, NULL
, HFILL
}
1316 { &xmcp_attr_domain
,
1317 { "Domain", "xmcp.attr.domain",
1318 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}
1322 /* Setup protocol subtree array */
1323 static gint
*ett
[] = {
1331 static ei_register_info ei
[] = {
1332 { &ei_xmcp_data_following_message_integrity
, { "xmcp.data_following_message_integrity", PI_PROTOCOL
, PI_WARN
, "Data following message-integrity", EXPFILL
}},
1333 { &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
}},
1334 { &ei_xmcp_attr_error_code_unusual
, { "xmcp.attr.error.unusual", PI_RESPONSE_CODE
, PI_WARN
, "Unusual error code", EXPFILL
}},
1335 { &ei_xmcp_attr_realm_incorrect
, { "xmcp.attr.realm.incorrect", PI_PROTOCOL
, PI_WARN
, "Incorrect Realm", EXPFILL
}},
1336 { &ei_xmcp_attr_length_bad
, { "xmcp.attr.length.bad", PI_PROTOCOL
, PI_WARN
, "Malformed IPv4 address", EXPFILL
}},
1337 { &ei_xmcp_xmcp_attr_servtrans_unknown
, { "xmcp.attr.service.transport.unknown", PI_PROTOCOL
, PI_WARN
, "Unknown transport type", EXPFILL
}},
1338 { &ei_xmcp_attr_type_unknown
, { "xmcp.attr.type.unknown", PI_PROTOCOL
, PI_NOTE
, "Unrecognized attribute type", EXPFILL
}},
1339 { &ei_xmcp_type_reserved_not_zero
, { "xmcp.type.reserved.not_zero", PI_PROTOCOL
, PI_WARN
, "First two bits not zero", EXPFILL
}},
1340 { &ei_xmcp_message_class_reserved
, { "xmcp.message_class.reserved", PI_PROTOCOL
, PI_WARN
, "Reserved message class", EXPFILL
}},
1341 { &ei_xmcp_error_response
, { "xmcp.error_response", PI_RESPONSE_CODE
, PI_NOTE
, "Error Response", EXPFILL
}},
1342 { &ei_xmcp_msg_type_method_reserved
, { "xmcp.msg_type_method.reserved", PI_PROTOCOL
, PI_WARN
, "Reserved message method", EXPFILL
}},
1343 { &ei_xmcp_length_bad
, { "xmcp.length.bad", PI_PROTOCOL
, PI_ERROR
, "XMCP message length exceeds packet length", EXPFILL
}},
1344 { &ei_xmcp_magic_cookie_incorrect
, { "xmcp.cookie.incorrect", PI_PROTOCOL
, PI_WARN
, "Magic cookie not correct for XMCP", EXPFILL
}},
1345 { &ei_xmcp_response_without_request
, { "xmcp.response_without_request", PI_SEQUENCE
, PI_NOTE
, "Response without corresponding request", EXPFILL
}},
1346 { &ei_xmcp_new_session
, { "xmcp.new_session", PI_SEQUENCE
, PI_CHAT
, "New session - Register", EXPFILL
}},
1347 { &ei_xmcp_session_termination
, { "xmcp.session_termination", PI_SEQUENCE
, PI_CHAT
, "Session termination", EXPFILL
}},
1350 module_t
*xmcp_module
;
1351 expert_module_t
* expert_xmcp
;
1353 proto_xmcp
= proto_register_protocol("eXtensible Messaging Client Protocol",
1356 proto_register_field_array(proto_xmcp
, hf
, array_length(hf
));
1357 proto_register_subtree_array(ett
, array_length(ett
));
1358 expert_xmcp
= expert_register_protocol(proto_xmcp
);
1359 expert_register_field_array(expert_xmcp
, ei
, array_length(ei
));
1361 /* Register XMCP configuration options */
1362 xmcp_module
= prefs_register_protocol(proto_xmcp
, proto_reg_handoff_xmcp
);
1364 prefs_register_uint_preference(xmcp_module
, "tcp.port", "XMCP TCP Port",
1365 "Set the port for XMCP messages (if other"
1366 " than the default of 4788)",
1367 10, &global_xmcp_tcp_port
);
1372 proto_reg_handoff_xmcp(void)
1374 static gboolean xmcp_prefs_initialized
= FALSE
;
1375 static dissector_handle_t xmcp_tcp_handle
;
1376 static guint xmcp_tcp_port
;
1378 if (!xmcp_prefs_initialized
) {
1379 xmcp_tcp_handle
= new_create_dissector_handle(dissect_xmcp_tcp
, proto_xmcp
);
1380 heur_dissector_add("tcp", dissect_xmcp_heur
, proto_xmcp
);
1381 media_type_dissector_table
= find_dissector_table("media_type");
1382 xmcp_prefs_initialized
= TRUE
;
1384 dissector_delete_uint("tcp.port", xmcp_tcp_port
, xmcp_tcp_handle
);
1387 xmcp_tcp_port
= global_xmcp_tcp_port
;
1388 dissector_add_uint("tcp.port", global_xmcp_tcp_port
, xmcp_tcp_handle
);
1392 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1397 * indent-tabs-mode: nil
1400 * vi: set shiftwidth=2 tabstop=8 expandtab:
1401 * :indentSize=2:tabSize=8:noTabs=true: