2 * Routines for Web Cache Coordination Protocol dissection
3 * Jerry Talkington <jtalkington@users.sourceforge.net>
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <epan/packet.h>
33 #include <epan/strutil.h>
34 #include "packet-wccp.h"
36 static int proto_wccp = -1;
37 static int hf_wccp_message_type = -1; /* the message type */
38 static int hf_wccp_version = -1; /* protocol version */
39 static int hf_hash_revision = -1; /* the version of the hash */
40 static int hf_change_num = -1; /* change number */
41 static int hf_recvd_id = -1;
42 static int hf_cache_ip = -1;
44 static gint ett_wccp = -1;
45 static gint ett_cache_count = -1;
46 static gint ett_buckets = -1;
47 static gint ett_flags = -1;
48 static gint ett_cache_info = -1;
49 static gint ett_security_info = -1;
50 static gint ett_service_info = -1;
51 static gint ett_service_flags = -1;
52 static gint ett_router_identity_element = -1;
53 static gint ett_router_identity_info = -1;
54 static gint ett_wc_identity_element = -1;
55 static gint ett_wc_identity_info = -1;
56 static gint ett_router_view_info = -1;
57 static gint ett_wc_view_info = -1;
58 static gint ett_router_assignment_element = -1;
59 static gint ett_router_assignment_info = -1;
60 static gint ett_query_info = -1;
61 static gint ett_capabilities_info = -1;
62 static gint ett_capability_element = -1;
63 static gint ett_capability_forwarding_method = -1;
64 static gint ett_capability_assignment_method = -1;
65 static gint ett_capability_return_method = -1;
66 static gint ett_unknown_info = -1;
71 * http://www.alternic.org/drafts/drafts-f-g/draft-forster-wrec-wccp-v1-00.html
73 * is a copy of the now-expired Internet-Draft for WCCP 1.0.
77 * http://search.ietf.org/internet-drafts/draft-wilson-wrec-wccp-v2-01.txt
79 * is an Internet-Draft for WCCP 2.0.
82 #define UDP_PORT_WCCP 2048
86 #define WCCP_HERE_I_AM 7
87 #define WCCP_I_SEE_YOU 8
88 #define WCCP_ASSIGN_BUCKET 9
89 #define WCCP2_HERE_I_AM 10
90 #define WCCP2_I_SEE_YOU 11
91 #define WCCP2_REDIRECT_ASSIGN 12
92 #define WCCP2_REMOVAL_QUERY 13
94 static const value_string wccp_type_vals[] = {
95 { WCCP_HERE_I_AM, "1.0 Here I am" },
96 { WCCP_I_SEE_YOU, "1.0 I see you" },
97 { WCCP_ASSIGN_BUCKET, "1.0 Assign bucket" },
98 { WCCP2_HERE_I_AM, "2.0 Here I am" },
99 { WCCP2_I_SEE_YOU, "2.0 I see you" },
100 { WCCP2_REDIRECT_ASSIGN, "2.0 Redirect assign" },
101 { WCCP2_REMOVAL_QUERY, "2.0 Removal query" },
105 static const value_string wccp_version_val[] = {
111 #define HASH_INFO_SIZE (4*(1+8+1))
113 #define WCCP_U_FLAG 0x80000000
115 #define WCCP2_SECURITY_INFO 0
116 #define WCCP2_SERVICE_INFO 1
117 #define WCCP2_ROUTER_ID_INFO 2
118 #define WCCP2_WC_ID_INFO 3
119 #define WCCP2_RTR_VIEW_INFO 4
120 #define WCCP2_WC_VIEW_INFO 5
121 #define WCCP2_REDIRECT_ASSIGNMENT 6
122 #define WCCP2_QUERY_INFO 7
123 #define WCCP2_CAPABILITIES_INFO 8
124 #define WCCP2_ALT_ASSIGNMENT 13
125 #define WCCP2_ASSIGN_MAP 14
126 #define WCCP2_COMMAND_EXTENSION 15
128 static const value_string info_type_vals[] = {
129 { WCCP2_SECURITY_INFO, "Security Info" },
130 { WCCP2_SERVICE_INFO, "Service Info" },
131 { WCCP2_ROUTER_ID_INFO, "Router Identity Info" },
132 { WCCP2_WC_ID_INFO, "Web-Cache Identity Info" },
133 { WCCP2_RTR_VIEW_INFO, "Router View Info" },
134 { WCCP2_WC_VIEW_INFO, "Web-Cache View Info" },
135 { WCCP2_REDIRECT_ASSIGNMENT, "Assignment Info" },
136 { WCCP2_QUERY_INFO, "Query Info" },
137 { WCCP2_CAPABILITIES_INFO, "Capabilities Info" },
138 { WCCP2_COMMAND_EXTENSION, "Command Extension" },
142 const value_string service_id_vals[] = {
147 typedef struct capability_flag {
149 const char *short_name;
150 const char *long_name;
153 static void dissect_hash_data(tvbuff_t *tvb, int offset,
154 proto_tree *wccp_tree);
155 static void dissect_web_cache_list_entry(tvbuff_t *tvb, int offset,
156 int index, proto_tree *wccp_tree);
157 static int wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree,
158 guint32 start, tvbuff_t *tvb, int offset);
159 static gchar *bucket_name(guint8 bucket);
160 static guint16 dissect_wccp2_header(tvbuff_t *tvb, int offset,
161 proto_tree *wccp_tree);
162 static void dissect_wccp2_info(tvbuff_t *tvb, int offset, guint16 length,
163 proto_tree *wccp_tree);
164 static gboolean dissect_wccp2_security_info(tvbuff_t *tvb, int offset,
165 int length, proto_tree *info_tree);
166 static gboolean dissect_wccp2_service_info(tvbuff_t *tvb, int offset,
167 int length, proto_tree *info_tree);
168 static gboolean dissect_wccp2_router_identity_info(tvbuff_t *tvb,
169 int offset, int length, proto_tree *info_tree);
170 static gboolean dissect_wccp2_wc_identity_info(tvbuff_t *tvb, int offset,
171 int length, proto_tree *info_tree);
172 static gboolean dissect_wccp2_router_view_info(tvbuff_t *tvb, int offset,
173 int length, proto_tree *info_tree);
174 static gboolean dissect_wccp2_wc_view_info(tvbuff_t *tvb, int offset,
175 int length, proto_tree *info_tree);
176 static gboolean dissect_wccp2_assignment_info(tvbuff_t *tvb, int offset,
177 int length, proto_tree *info_tree);
178 static gboolean dissect_wccp2_router_query_info(tvbuff_t *tvb, int offset,
179 int length, proto_tree *info_tree);
180 static gboolean dissect_wccp2_capability_info(tvbuff_t *tvb, int offset,
181 int length, proto_tree *info_tree);
182 static void dissect_32_bit_capability_flags(tvbuff_t *tvb, int curr_offset,
183 guint16 capability_val_len, gint ett, const capability_flag *flags,
184 proto_tree *element_tree);
187 dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
190 proto_tree *wccp_tree = NULL;
191 proto_item *wccp_tree_item;
192 guint32 wccp_message_type;
198 if(check_col(pinfo->cinfo, COL_PROTOCOL)) {
199 col_set_str(pinfo->cinfo, COL_PROTOCOL, "WCCP");
201 if(check_col(pinfo->cinfo, COL_INFO)) {
202 col_clear(pinfo->cinfo, COL_INFO);
205 wccp_message_type = tvb_get_ntohl(tvb, offset);
207 if(check_col(pinfo->cinfo, COL_INFO)) {
208 col_add_str(pinfo->cinfo, COL_INFO, val_to_str(wccp_message_type,
209 wccp_type_vals, "Unknown WCCP message (%u)"));
213 wccp_tree_item = proto_tree_add_item(tree, proto_wccp, tvb, offset,
215 wccp_tree = proto_item_add_subtree(wccp_tree_item, ett_wccp);
217 proto_tree_add_uint(wccp_tree, hf_wccp_message_type, tvb, offset,
218 sizeof(wccp_message_type), wccp_message_type);
219 offset += sizeof(wccp_message_type);
221 switch (wccp_message_type) {
224 proto_tree_add_item(wccp_tree, hf_wccp_version, tvb,
227 dissect_hash_data(tvb, offset, wccp_tree);
228 offset += HASH_INFO_SIZE;
229 proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
235 proto_tree_add_item(wccp_tree, hf_wccp_version, tvb,
238 proto_tree_add_item(wccp_tree, hf_change_num, tvb, offset,
241 proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
244 cache_count = tvb_get_ntohl(tvb, offset);
245 proto_tree_add_text(wccp_tree, tvb, offset, 4,
246 "Number of Web Caches: %u", cache_count);
248 for (i = 0; i < cache_count; i++) {
249 dissect_web_cache_list_entry(tvb, offset, i,
251 offset += 4 + HASH_INFO_SIZE;
255 case WCCP_ASSIGN_BUCKET:
257 * This hasn't been tested, since I don't have any
258 * traces with this in it.
260 * The V1 spec claims that this does, indeed,
261 * have a Received ID field after the type,
262 * rather than a Version field.
264 proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
267 cache_count = tvb_get_ntohl(tvb, offset);
268 proto_tree_add_text(wccp_tree, tvb, offset, 4,
269 "Number of Web Caches: %u", cache_count);
271 for (i = 0; i < cache_count; i++) {
272 tvb_memcpy(tvb, (guint8 *)&ipaddr, offset, 4);
273 proto_tree_add_ipv4_format(wccp_tree,
274 hf_cache_ip, tvb, offset, 4,
276 "Web Cache %d IP Address: %s", i,
277 ip_to_str((guint8 *)&ipaddr));
280 for (i = 0; i < 256; i += 4) {
281 proto_tree_add_text(wccp_tree, tvb, offset, 4,
282 "Buckets %d - %d: %10s %10s %10s %10s",
284 bucket_name(tvb_get_guint8(tvb, offset)),
285 bucket_name(tvb_get_guint8(tvb, offset+1)),
286 bucket_name(tvb_get_guint8(tvb, offset+2)),
287 bucket_name(tvb_get_guint8(tvb, offset+3)));
292 case WCCP2_HERE_I_AM:
293 case WCCP2_I_SEE_YOU:
294 case WCCP2_REMOVAL_QUERY:
295 case WCCP2_REDIRECT_ASSIGN:
296 default: /* assume unknown packets are v2 */
297 length = dissect_wccp2_header(tvb, offset, wccp_tree);
299 dissect_wccp2_info(tvb, offset, length, wccp_tree);
306 dissect_hash_data(tvbuff_t *tvb, int offset, proto_tree *wccp_tree)
308 proto_item *bucket_item;
309 proto_tree *bucket_tree;
311 proto_tree *field_tree;
317 proto_tree_add_item(wccp_tree, hf_hash_revision, tvb, offset, 4,
321 bucket_item = proto_tree_add_text(wccp_tree, tvb, offset, 32,
323 bucket_tree = proto_item_add_subtree(bucket_item, ett_buckets);
325 for (i = 0, n = 0; i < 32; i++) {
326 bucket_info = tvb_get_guint8(tvb, offset);
327 n = wccp_bucket_info(bucket_info, bucket_tree, n, tvb, offset);
330 flags = tvb_get_ntohl(tvb, offset);
331 tf = proto_tree_add_text(wccp_tree, tvb, offset, 4,
332 "Flags: 0x%08X (%s)", flags,
333 ((flags & WCCP_U_FLAG) ?
334 "Hash information is historical" :
335 "Hash information is current"));
336 field_tree = proto_item_add_subtree(tf, ett_flags);
337 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
338 decode_boolean_bitfield(flags, WCCP_U_FLAG,
340 "Hash information is historical",
341 "Hash information is current"));
345 dissect_web_cache_list_entry(tvbuff_t *tvb, int offset, int index,
346 proto_tree *wccp_tree)
349 proto_tree *list_entry_tree;
351 tl = proto_tree_add_text(wccp_tree, tvb, offset, 4 + HASH_INFO_SIZE,
352 "Web-Cache List Entry(%d)", index);
353 list_entry_tree = proto_item_add_subtree(tl, ett_cache_info);
354 proto_tree_add_item(list_entry_tree, hf_cache_ip, tvb, offset, 4,
356 dissect_hash_data(tvb, offset + 4, list_entry_tree);
361 * takes an integer representing a "Hash Information" bitmap, and spits out
362 * the corresponding proto_tree entries, returning the next bucket number.
365 wccp_bucket_info(guint8 bucket_info, proto_tree *bucket_tree, guint32 start,
366 tvbuff_t *tvb, int offset)
370 for(i = 0; i < 8; i++) {
371 proto_tree_add_text(bucket_tree, tvb, offset, sizeof(bucket_info), "Bucket %3d: %s", start, (bucket_info & 1<<i ? "Assigned" : "Not Assigned") );
378 bucket_name(guint8 bucket)
380 static gchar str[4][10+1];
383 if (cur == &str[0][0])
385 else if (cur == &str[1][0])
387 else if (cur == &str[2][0])
392 strcpy(cur, "Unassigned");
394 sprintf(cur, "%u", bucket);
399 dissect_wccp2_header(tvbuff_t *tvb, int offset, proto_tree *wccp_tree)
403 proto_tree_add_item(wccp_tree, hf_wccp_version, tvb, offset, 2,
406 length = tvb_get_ntohs(tvb, offset);
407 proto_tree_add_text(wccp_tree, tvb, offset, 2, "Length: %u",
413 dissect_wccp2_info(tvbuff_t *tvb, int offset, guint16 length,
414 proto_tree *wccp_tree)
419 proto_tree *info_tree;
421 gboolean (*dissector)(tvbuff_t *, int, int, proto_tree *);
423 while (length != 0) {
424 type = tvb_get_ntohs(tvb, offset);
425 item_length = tvb_get_ntohs(tvb, offset+2);
429 case WCCP2_SECURITY_INFO:
430 ett = ett_security_info;
431 dissector = dissect_wccp2_security_info;
434 case WCCP2_SERVICE_INFO:
435 ett = ett_service_info;
436 dissector = dissect_wccp2_service_info;
439 case WCCP2_ROUTER_ID_INFO:
440 ett = ett_router_identity_info;
441 dissector = dissect_wccp2_router_identity_info;
444 case WCCP2_WC_ID_INFO:
445 ett = ett_wc_identity_info;
446 dissector = dissect_wccp2_wc_identity_info;
449 case WCCP2_RTR_VIEW_INFO:
450 ett = ett_router_view_info;
451 dissector = dissect_wccp2_router_view_info;
454 case WCCP2_WC_VIEW_INFO:
455 ett = ett_wc_view_info;
456 dissector = dissect_wccp2_wc_view_info;
459 case WCCP2_REDIRECT_ASSIGNMENT:
460 ett = ett_router_assignment_info;
461 dissector = dissect_wccp2_assignment_info;
464 case WCCP2_QUERY_INFO:
465 ett = ett_query_info;
466 dissector = dissect_wccp2_router_query_info;
469 case WCCP2_CAPABILITIES_INFO:
470 ett = ett_capabilities_info;
471 dissector = dissect_wccp2_capability_info;
475 ett = ett_unknown_info;
480 ti = proto_tree_add_text(wccp_tree, tvb, offset, item_length + 4,
481 val_to_str(type, info_type_vals, "Unknown info type (%u)"));
482 info_tree = proto_item_add_subtree(ti, ett);
483 proto_tree_add_text(info_tree, tvb, offset, 2,
485 val_to_str(type, info_type_vals, "Unknown info type (%u)"));
486 proto_tree_add_text(info_tree, tvb, offset+2, 2,
487 "Length: %u", item_length);
492 * XXX - pass in "length" and check for that as well.
494 if (dissector != NULL) {
495 if (!(*dissector)(tvb, offset, item_length, info_tree))
496 return; /* ran out of data */
498 proto_tree_add_text(info_tree, tvb, offset, item_length,
499 "Data: %u byte%s", item_length,
500 plurality(item_length, "", "s"));
502 offset += item_length;
503 length -= item_length;
507 #define SECURITY_INFO_LEN 4
509 #define WCCP2_NO_SECURITY 0
510 #define WCCP2_MD5_SECURITY 1
513 dissect_wccp2_security_info(tvbuff_t *tvb, int offset, int length,
514 proto_tree *info_tree)
516 guint32 security_option;
518 if (length < SECURITY_INFO_LEN) {
519 proto_tree_add_text(info_tree, tvb, offset, 0,
520 "Item length is %u, should be %u", length,
525 security_option = tvb_get_ntohl(tvb, offset);
526 switch (security_option) {
528 case WCCP2_NO_SECURITY:
529 proto_tree_add_text(info_tree, tvb, offset, 4,
530 "Security Option: None");
533 case WCCP2_MD5_SECURITY:
534 proto_tree_add_text(info_tree, tvb, offset, 4,
535 "Security Option: MD5");
538 proto_tree_add_text(info_tree, tvb, offset,
539 length - 4, "MD5 checksum: %s",
540 tvb_bytes_to_str(tvb, offset, length - 4));
545 proto_tree_add_text(info_tree, tvb, offset, 4,
546 "Security Option: Unknown (%u)", security_option);
552 #define SERVICE_INFO_LEN (4+4+8*2)
554 #define WCCP2_SERVICE_STANDARD 0
555 #define WCCP2_SERVICE_DYNAMIC 1
560 #define WCCP2_SI_SRC_IP_HASH 0x0001
561 #define WCCP2_SI_DST_IP_HASH 0x0002
562 #define WCCP2_SI_SRC_PORT_HASH 0x0004
563 #define WCCP2_SI_DST_PORT_HASH 0x0008
564 #define WCCP2_SI_PORTS_DEFINED 0x0010
565 #define WCCP2_SI_PORTS_SOURCE 0x0020
566 #define WCCP2_SI_SRC_IP_ALT_HASH 0x0100
567 #define WCCP2_SI_DST_IP_ALT_HASH 0x0200
568 #define WCCP2_SI_SRC_PORT_ALT_HASH 0x0400
569 #define WCCP2_SI_DST_PORT_ALT_HASH 0x0800
572 dissect_wccp2_service_info(tvbuff_t *tvb, int offset, int length,
573 proto_tree *info_tree)
578 proto_tree *field_tree;
581 if (length != SERVICE_INFO_LEN) {
582 proto_tree_add_text(info_tree, tvb, offset, 0,
583 "Item length is %u, should be %u", length,
588 service_type = tvb_get_guint8(tvb, offset);
589 switch (service_type) {
591 case WCCP2_SERVICE_STANDARD:
592 proto_tree_add_text(info_tree, tvb, offset, 1,
593 "Service Type: Well-known service");
594 proto_tree_add_text(info_tree, tvb, offset+1, 1,
596 val_to_str(tvb_get_guint8(tvb, offset+1), service_id_vals,
597 "Unknown (0x%02X)"));
601 case WCCP2_SERVICE_DYNAMIC:
602 proto_tree_add_text(info_tree, tvb, offset, 1,
603 "Service Type: Dynamic service");
604 proto_tree_add_text(info_tree, tvb, offset+1, 1,
606 val_to_str(tvb_get_guint8(tvb, offset+1), service_id_vals,
607 "Unknown (0x%02X)"));
608 proto_tree_add_text(info_tree, tvb, offset+2, 1,
609 "Priority: %u", tvb_get_guint8(tvb, offset+2));
611 * XXX - does "IP protocol identifier" mean this is a
612 * protocol type of the sort you get in IP headers?
613 * If so, we should get a table of those from the
614 * IP dissector, and use that.
616 proto_tree_add_text(info_tree, tvb, offset+3, 1,
617 "Protocol: %u", tvb_get_guint8(tvb, offset+3)); /* IP protocol identifier */
621 proto_tree_add_text(info_tree, tvb, offset, 1,
622 "Service Type: Unknown (%u)", service_type);
627 flags = tvb_get_ntohl(tvb, offset);
628 tf = proto_tree_add_text(info_tree, tvb, offset, 4,
629 "Flags: 0x%08X", flags);
630 field_tree = proto_item_add_subtree(tf, ett_service_flags);
631 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
632 decode_boolean_bitfield(flags, WCCP2_SI_SRC_IP_HASH,
634 "Use source IP address in primary hash",
635 "Don't use source IP address in primary hash"));
636 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
637 decode_boolean_bitfield(flags, WCCP2_SI_DST_IP_HASH,
639 "Use destination IP address in primary hash",
640 "Don't use destination IP address in primary hash"));
641 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
642 decode_boolean_bitfield(flags, WCCP2_SI_SRC_PORT_HASH,
644 "Use source port in primary hash",
645 "Don't use source port in primary hash"));
646 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
647 decode_boolean_bitfield(flags, WCCP2_SI_DST_PORT_HASH,
649 "Use destination port in primary hash",
650 "Don't use destination port in primary hash"));
651 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
652 decode_boolean_bitfield(flags, WCCP2_SI_PORTS_DEFINED,
655 "Ports not defined"));
656 if (flags & WCCP2_SI_PORTS_DEFINED) {
657 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
658 decode_boolean_bitfield(flags, WCCP2_SI_PORTS_SOURCE,
660 "Ports refer to source port",
661 "Ports refer to destination port"));
663 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
664 decode_boolean_bitfield(flags, WCCP2_SI_SRC_IP_ALT_HASH,
666 "Use source IP address in secondary hash",
667 "Don't use source IP address in secondary hash"));
668 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
669 decode_boolean_bitfield(flags, WCCP2_SI_DST_IP_ALT_HASH,
671 "Use destination IP address in secondary hash",
672 "Don't use destination IP address in secondary hash"));
673 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
674 decode_boolean_bitfield(flags, WCCP2_SI_SRC_PORT_ALT_HASH,
676 "Use source port in secondary hash",
677 "Don't use source port in secondary hash"));
678 proto_tree_add_text(field_tree, tvb, offset, 4, "%s",
679 decode_boolean_bitfield(flags, WCCP2_SI_DST_PORT_ALT_HASH,
681 "Use destination port in secondary hash",
682 "Don't use destination port in secondary hash"));
685 if (flags & WCCP2_SI_PORTS_DEFINED) {
686 for (i = 0; i < 8; i++) {
687 proto_tree_add_text(info_tree, tvb, offset, 2,
688 "Port %d: %u", i, tvb_get_ntohs(tvb, offset));
696 #define ROUTER_ID_INFO_MIN_LEN (8+4+4)
699 dissect_wccp2_router_identity_element(tvbuff_t *tvb, int offset,
702 proto_tree_add_text(tree, tvb, offset, 4,
703 "IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
704 proto_tree_add_text(tree, tvb, offset + 4, 4,
705 "Receive ID: %u", tvb_get_ntohl(tvb, offset + 4));
709 dissect_wccp2_router_identity_info(tvbuff_t *tvb, int offset, int length,
710 proto_tree *info_tree)
712 guint32 n_received_from;
715 proto_tree *element_tree;
717 if (length < ROUTER_ID_INFO_MIN_LEN) {
718 proto_tree_add_text(info_tree, tvb, offset, 0,
719 "Item length is %u, should be >= %u", length,
720 ROUTER_ID_INFO_MIN_LEN);
724 te = proto_tree_add_text(info_tree, tvb, offset, 8,
725 "Router Identity Element: IP address %s",
726 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
727 element_tree = proto_item_add_subtree(te,
728 ett_router_identity_element);
729 dissect_wccp2_router_identity_element(tvb, offset, element_tree);
732 proto_tree_add_text(info_tree, tvb, offset, 4,
733 "Sent To IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
736 n_received_from = tvb_get_ntohl(tvb, offset);
737 proto_tree_add_text(info_tree, tvb, offset, 4,
738 "Number of Received From IP addresses: %u", n_received_from);
741 for (i = 0; i < n_received_from; i++) {
742 proto_tree_add_text(info_tree, tvb, offset, 4,
743 "Received From IP Address %d: %s", i,
744 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
751 #define WC_ID_INFO_LEN (4+4+8*4+4)
754 dissect_wccp2_web_cache_identity_element(tvbuff_t *tvb, int offset,
757 proto_item *bucket_item;
758 proto_tree *bucket_tree;
760 proto_tree *field_tree;
766 proto_tree_add_text(tree, tvb, offset, 4,
767 "Web-Cache IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
770 proto_tree_add_text(tree, tvb, offset, 2,
771 "Hash Revision %u", tvb_get_ntohs(tvb, offset));
774 flags = tvb_get_ntohs(tvb, offset);
775 tf = proto_tree_add_text(tree, tvb, offset, 2,
776 "Flags: 0x%04X (%s)", flags,
778 "Hash information is historical" :
779 "Hash information is current"));
780 field_tree = proto_item_add_subtree(tf, ett_flags);
781 proto_tree_add_text(field_tree, tvb, offset, 2, "%s",
782 decode_boolean_bitfield(flags, 0x8000,
784 "Hash information is historical",
785 "Hash information is current"));
788 bucket_item = proto_tree_add_text(tree, tvb, offset, 8*4,
790 bucket_tree = proto_item_add_subtree(bucket_item, ett_buckets);
791 for (i = 0, n = 0; i < 32; i++) {
792 bucket_info = tvb_get_guint8(tvb, offset);
793 n = wccp_bucket_info(bucket_info, bucket_tree, n, tvb, offset);
797 proto_tree_add_text(tree, tvb, offset, 2,
798 "Assignment Weight: %u", tvb_get_ntohs(tvb, offset));
801 proto_tree_add_text(tree, tvb, offset, 2,
802 "Status: 0x%04X", tvb_get_ntohs(tvb, offset));
809 dissect_wccp2_wc_identity_info(tvbuff_t *tvb, int offset, int length,
810 proto_tree *info_tree)
813 proto_tree *element_tree;
815 if (length != WC_ID_INFO_LEN) {
816 proto_tree_add_text(info_tree, tvb, offset, 0,
817 "Item length is %u, should be %u", length, WC_ID_INFO_LEN);
821 te = proto_tree_add_text(info_tree, tvb, offset, 4+2+2+32+2+2,
822 "Web-Cache Identity Element: IP address %s",
823 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
824 element_tree = proto_item_add_subtree(te, ett_wc_identity_element);
825 if (!dissect_wccp2_web_cache_identity_element(tvb, offset,
827 return FALSE; /* ran out of data */
832 #define ROUTER_VIEW_INFO_MIN_LEN (4+8+4)
835 dissect_wccp2_assignment_key(tvbuff_t *tvb, int offset,
836 proto_tree *info_tree)
838 proto_tree_add_text(info_tree, tvb, offset, 4,
839 "Assignment Key IP Address: %s",
840 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
841 proto_tree_add_text(info_tree, tvb, offset + 4, 4,
842 "Assignment Key Change Number: %u", tvb_get_ntohl(tvb, offset + 4));
846 dissect_wccp2_router_view_info(tvbuff_t *tvb, int offset, int length,
847 proto_tree *info_tree)
850 guint32 n_web_caches;
853 proto_tree *element_tree;
855 if (length < ROUTER_VIEW_INFO_MIN_LEN) {
856 proto_tree_add_text(info_tree, tvb, offset, 0,
857 "Item length is %u, should be >= %u", length,
858 ROUTER_VIEW_INFO_MIN_LEN);
862 proto_tree_add_text(info_tree, tvb, offset, 4,
863 "Member Change Number: %u", tvb_get_ntohl(tvb, offset));
866 dissect_wccp2_assignment_key(tvb, offset, info_tree);
869 n_routers = tvb_get_ntohl(tvb, offset);
870 proto_tree_add_text(info_tree, tvb, offset, 4,
871 "Number of Routers: %u", n_routers);
874 for (i = 0; i < n_routers; i++) {
875 proto_tree_add_text(info_tree, tvb, offset, 4,
876 "Router %d IP Address: %s", i,
877 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
881 n_web_caches = tvb_get_ntohl(tvb, offset);
882 proto_tree_add_text(info_tree, tvb, offset, 4,
883 "Number of Web Caches: %u", n_web_caches);
886 for (i = 0; i < n_web_caches; i++) {
887 te = proto_tree_add_text(info_tree, tvb, offset, WC_ID_INFO_LEN,
888 "Web-Cache Identity Element %d: IP address %s", i,
889 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
890 element_tree = proto_item_add_subtree(te,
891 ett_wc_identity_element);
892 if (!dissect_wccp2_web_cache_identity_element(tvb,
893 offset, element_tree))
894 return FALSE; /* ran out of data */
895 offset += WC_ID_INFO_LEN;
901 #define WC_VIEW_INFO_MIN_LEN (4+4)
904 dissect_wccp2_wc_view_info(tvbuff_t *tvb, int offset, int length,
905 proto_tree *info_tree)
908 guint32 n_web_caches;
911 proto_tree *element_tree;
913 if (length < WC_VIEW_INFO_MIN_LEN) {
914 proto_tree_add_text(info_tree, tvb, offset, 0,
915 "Item length is %u, should be >= %u", length,
916 WC_VIEW_INFO_MIN_LEN);
920 proto_tree_add_text(info_tree, tvb, offset, 4,
921 "Change Number: %u", tvb_get_ntohl(tvb, offset));
924 n_routers = tvb_get_ntohl(tvb, offset);
925 proto_tree_add_text(info_tree, tvb, offset, 4,
926 "Number of Routers: %u", n_routers);
929 for (i = 0; i < n_routers; i++) {
930 te = proto_tree_add_text(info_tree, tvb, offset, 8,
931 "Router %d Identity Element: IP address %s", i,
932 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
933 element_tree = proto_item_add_subtree(te,
934 ett_router_identity_element);
935 dissect_wccp2_router_identity_element(tvb, offset, element_tree);
939 n_web_caches = tvb_get_ntohl(tvb, offset);
940 proto_tree_add_text(info_tree, tvb, offset, 4,
941 "Number of Web Caches: %u", n_web_caches);
944 for (i = 0; i < n_web_caches; i++) {
945 proto_tree_add_text(info_tree, tvb, offset, 4,
946 "Web-Cache %d: IP address %s", i,
947 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
954 #define ASSIGNMENT_INFO_MIN_LEN (8+4)
957 dissect_wccp2_router_assignment_element(tvbuff_t *tvb, int offset,
960 proto_tree_add_text(tree, tvb, offset, 4,
961 "IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
962 proto_tree_add_text(tree, tvb, offset + 4, 4,
963 "Receive ID: %u", tvb_get_ntohl(tvb, offset + 4));
964 proto_tree_add_text(tree, tvb, offset + 8, 4,
965 "Change Number: %u", tvb_get_ntohl(tvb, offset + 8));
969 assignment_bucket_name(guint8 bucket)
971 static gchar str[4][10+1];
974 if (cur == &str[0][0])
976 else if (cur == &str[1][0])
978 else if (cur == &str[2][0])
983 strcpy(cur, "Unassigned");
985 sprintf(cur, "%u%s", bucket >> 1,
986 (bucket & 0x01) ? " (Alt)" : "");
992 dissect_wccp2_assignment_info(tvbuff_t *tvb, int offset, int length,
993 proto_tree *info_tree)
996 guint32 n_web_caches;
999 proto_tree *element_tree;
1001 if (length < ASSIGNMENT_INFO_MIN_LEN) {
1002 proto_tree_add_text(info_tree, tvb, offset, 0,
1003 "Item length is %u, should be >= %u", length,
1004 ASSIGNMENT_INFO_MIN_LEN);
1008 dissect_wccp2_assignment_key(tvb, offset, info_tree);
1011 n_routers = tvb_get_ntohl(tvb, offset);
1012 proto_tree_add_text(info_tree, tvb, offset, 4,
1013 "Number of Routers: %u", n_routers);
1016 for (i = 0; i < n_routers; i++) {
1017 te = proto_tree_add_text(info_tree, tvb, offset, 4,
1018 "Router %d Assignment Element: IP address %s", i,
1019 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1020 element_tree = proto_item_add_subtree(te,
1021 ett_router_assignment_element);
1022 dissect_wccp2_router_assignment_element(tvb, offset,
1027 n_web_caches = tvb_get_ntohl(tvb, offset);
1028 proto_tree_add_text(info_tree, tvb, offset, 4,
1029 "Number of Web Caches: %u", n_web_caches);
1032 for (i = 0; i < n_web_caches; i++) {
1033 proto_tree_add_text(info_tree, tvb, offset, 4,
1034 "Web-Cache %d: IP address %s", i,
1035 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1039 for (i = 0; i < 256; i += 4) {
1040 proto_tree_add_text(info_tree, tvb, offset, 4,
1041 "Buckets %d - %d: %10s %10s %10s %10s",
1043 assignment_bucket_name(tvb_get_guint8(tvb, offset)),
1044 assignment_bucket_name(tvb_get_guint8(tvb, offset+1)),
1045 assignment_bucket_name(tvb_get_guint8(tvb, offset+2)),
1046 assignment_bucket_name(tvb_get_guint8(tvb, offset+3)));
1053 #define QUERY_INFO_LEN (4+4+4+4)
1056 dissect_wccp2_router_query_info(tvbuff_t *tvb, int offset, int length,
1057 proto_tree *info_tree)
1059 if (length != QUERY_INFO_LEN) {
1060 proto_tree_add_text(info_tree, tvb, offset, 0,
1061 "Item length is %u, should be %u", length, QUERY_INFO_LEN);
1065 proto_tree_add_text(info_tree, tvb, offset, 4,
1066 "Router IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1069 proto_tree_add_text(info_tree, tvb, offset, 4,
1070 "Receive ID: %u", tvb_get_ntohl(tvb, offset));
1073 proto_tree_add_text(info_tree, tvb, offset, 4,
1074 "Sent To IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1077 proto_tree_add_text(info_tree, tvb, offset, 4,
1078 "Target IP Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1084 #define WCCP2_FORWARDING_METHOD 0x01
1085 #define WCCP2_ASSIGNMENT_METHOD 0x02
1086 #define WCCP2_PACKET_RETURN_METHOD 0x03
1088 static const value_string capability_type_vals[] = {
1089 { WCCP2_FORWARDING_METHOD, "Forwarding Method" },
1090 { WCCP2_ASSIGNMENT_METHOD, "Assignment Method" },
1091 { WCCP2_PACKET_RETURN_METHOD, "Return Method" },
1095 #define WCCP2_FORWARDING_METHOD_GRE 0x00000001
1096 #define WCCP2_FORWARDING_METHOD_L2 0x00000002
1098 static const capability_flag forwarding_method_flags[] = {
1099 { WCCP2_FORWARDING_METHOD_GRE,
1100 "IP-GRE", "GRE-encapsulated" },
1101 { WCCP2_FORWARDING_METHOD_L2,
1102 "L2", "L2 rewrite" },
1107 #define WCCP2_ASSIGNMENT_METHOD_HASH 0x00000001
1108 #define WCCP2_ASSIGNMENT_METHOD_MASK 0x00000002
1110 static const capability_flag assignment_method_flags[] = {
1111 { WCCP2_ASSIGNMENT_METHOD_HASH, "Hash", "Hash" },
1112 { WCCP2_ASSIGNMENT_METHOD_MASK, "Mask", "Mask" },
1116 #define WCCP2_PACKET_RETURN_METHOD_GRE 0x00000001
1117 #define WCCP2_PACKET_RETURN_METHOD_L2 0x00000002
1119 static const capability_flag packet_return_method_flags[] = {
1120 { WCCP2_PACKET_RETURN_METHOD_GRE,
1121 "IP-GRE", "GRE-encapsulated" },
1122 { WCCP2_PACKET_RETURN_METHOD_L2,
1123 "L2", "L2 rewrite" },
1129 dissect_wccp2_capability_info(tvbuff_t *tvb, int offset, int length,
1130 proto_tree *info_tree)
1132 guint16 capability_type;
1133 guint16 capability_val_len;
1136 proto_tree *element_tree;
1138 for (curr_offset = offset; curr_offset < (length + offset);
1139 curr_offset += (capability_val_len + 4)) {
1140 capability_type = tvb_get_ntohs(tvb, curr_offset);
1141 capability_val_len = tvb_get_ntohs(tvb, curr_offset + 2);
1142 te = proto_tree_add_text(info_tree, tvb, curr_offset,
1143 capability_val_len + 4, "%s",
1144 val_to_str(capability_type,
1145 capability_type_vals, "Unknown Capability Element (0x%08X)"));
1146 element_tree = proto_item_add_subtree(te,
1147 ett_capability_element);
1149 proto_tree_add_text(element_tree, tvb, curr_offset, 2,
1151 val_to_str(capability_type,
1152 capability_type_vals, "Unknown (0x%08X)"));
1154 if (capability_val_len < 4) {
1155 proto_tree_add_text(element_tree, tvb, curr_offset+2, 2,
1156 "Value Length: %u (illegal, must be >= 4)",
1157 capability_val_len);
1160 proto_tree_add_text(element_tree, tvb, curr_offset+2, 2,
1161 "Value Length: %u", capability_val_len);
1163 switch (capability_type) {
1165 case WCCP2_FORWARDING_METHOD:
1166 dissect_32_bit_capability_flags(tvb, curr_offset,
1168 ett_capability_forwarding_method,
1169 forwarding_method_flags, element_tree);
1172 case WCCP2_ASSIGNMENT_METHOD:
1173 dissect_32_bit_capability_flags(tvb, curr_offset,
1175 ett_capability_assignment_method,
1176 assignment_method_flags, element_tree);
1179 case WCCP2_PACKET_RETURN_METHOD:
1180 dissect_32_bit_capability_flags(tvb, curr_offset,
1182 ett_capability_return_method,
1183 packet_return_method_flags, element_tree);
1187 proto_tree_add_text(element_tree, tvb,
1188 curr_offset+4, capability_val_len,
1190 tvb_bytes_to_str(tvb, curr_offset+4,
1191 capability_val_len));
1200 dissect_32_bit_capability_flags(tvbuff_t *tvb, int curr_offset,
1201 guint16 capability_val_len, gint ett, const capability_flag *flags,
1202 proto_tree *element_tree)
1204 guint32 capability_val;
1206 proto_tree *method_tree;
1208 char flags_string[128+1];
1213 if (capability_val_len != 4) {
1214 proto_tree_add_text(element_tree, tvb,
1215 curr_offset+4, capability_val_len,
1216 "Illegal length (must be 4)");
1220 capability_val = tvb_get_ntohl(tvb, curr_offset + 4);
1221 flags_string[0] = '\0';
1222 p = &flags_string[0];
1223 space_left = sizeof flags_string;
1224 for (i = 0; flags[i].short_name != NULL; i++) {
1225 if (capability_val & flags[i].value) {
1226 if (p != &flags_string[0]) {
1227 g_snprintf(p, space_left, ",");
1228 p = &flags_string[strlen(flags_string)];
1230 g_snprintf(p, space_left, "%s", flags[i].short_name);
1231 p = &flags_string[strlen(flags_string)];
1234 tm = proto_tree_add_text(element_tree, tvb, curr_offset+4, 4,
1235 "Value: 0x%08X (%s)", capability_val, flags_string);
1236 method_tree = proto_item_add_subtree(tm, ett);
1237 for (i = 0; flags[i].long_name != NULL; i++) {
1238 p = decode_bitfield_value(buf, capability_val,
1239 flags[i].value, 32);
1240 strcpy(p, flags[i].long_name);
1242 if (capability_val & flags[i].value)
1243 strcat(p, "Supported");
1245 strcat(p, "Not supported");
1246 proto_tree_add_text(method_tree, tvb, curr_offset+4, 4,
1252 proto_register_wccp(void)
1254 static hf_register_info hf[] = {
1255 { &hf_wccp_message_type,
1256 { "WCCP Message Type", "wccp.message", FT_UINT32, BASE_DEC, VALS(wccp_type_vals), 0x0,
1257 "The WCCP message that was sent", HFILL }
1260 { "WCCP Version", "wccp.version", FT_UINT32, BASE_HEX, VALS(wccp_version_val), 0x0,
1261 "The WCCP version", HFILL }
1263 { &hf_hash_revision,
1264 { "Hash Revision", "wccp.hash_revision", FT_UINT32, BASE_DEC, 0x0, 0x0,
1265 "The cache hash revision", HFILL }
1268 { "Change Number", "wccp.change_num", FT_UINT32, BASE_DEC, 0x0, 0x0,
1269 "The Web-Cache list entry change number", HFILL }
1272 { "Received ID", "wccp.recvd_id", FT_UINT32, BASE_DEC, 0x0, 0x0,
1273 "The number of I_SEE_YOU's that have been sent", HFILL }
1276 { "Web Cache IP address", "wccp.cache_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
1277 "The IP address of a Web cache", HFILL }
1280 static gint *ett[] = {
1289 &ett_router_identity_element,
1290 &ett_router_identity_info,
1291 &ett_wc_identity_element,
1292 &ett_wc_identity_info,
1293 &ett_router_view_info,
1296 &ett_router_assignment_element,
1297 &ett_router_assignment_info,
1298 &ett_capabilities_info,
1299 &ett_capability_element,
1300 &ett_capability_forwarding_method,
1301 &ett_capability_assignment_method,
1302 &ett_capability_return_method,
1306 proto_wccp = proto_register_protocol("Web Cache Coordination Protocol",
1308 proto_register_field_array(proto_wccp, hf, array_length(hf));
1309 proto_register_subtree_array(ett, array_length(ett));
1313 proto_reg_handoff_wccp(void)
1315 dissector_handle_t wccp_handle;
1317 wccp_handle = create_dissector_handle(dissect_wccp, proto_wccp);
1318 dissector_add("udp.port", UDP_PORT_WCCP, wccp_handle);