2 * DEBUG: section 80 WCCP Support
3 * AUTHOR: Steven Wilton
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
38 #include "comm/Connection.h"
39 #include "compat/strsep.h"
41 #include "ip/Address.h"
50 #define WCCP_PORT 2048
51 #define WCCP_RESPONSE_SIZE 12448
52 #define WCCP_BUCKETS 256
54 static int theWccp2Connection
= -1;
55 static int wccp2_connected
= 0;
57 static PF wccp2HandleUdp
;
58 static EVH wccp2HereIam
;
59 static EVH wccp2AssignBuckets
;
63 #define WCCP2_HASH_ASSIGNMENT 0x00
64 #define WCCP2_MASK_ASSIGNMENT 0x01
66 #define WCCP2_NONE_SECURITY_LEN 0
67 #define WCCP2_MD5_SECURITY_LEN 16
70 #define WCCP2_NUMPORTS 8
71 #define WCCP2_PASSWORD_LEN 8
74 /* WCCPv2 Pakcet format structures */
75 /* Defined in draft-wilson-wccp-v2-12-oct-2001.txt */
78 /** \interface WCCPv2_Protocol
79 * Generic header struct
81 struct wccp2_item_header_t
{
86 /* item type values */
87 #define WCCP2_SECURITY_INFO 0
88 #define WCCP2_SERVICE_INFO 1
89 #define WCCP2_ROUTER_ID_INFO 2
90 #define WCCP2_WC_ID_INFO 3
91 #define WCCP2_RTR_VIEW_INFO 4
92 #define WCCP2_WC_VIEW_INFO 5
93 #define WCCP2_REDIRECT_ASSIGNMENT 6
94 #define WCCP2_QUERY_INFO 7
95 #define WCCP2_CAPABILITY_INFO 8
96 #define WCCP2_ALT_ASSIGNMENT 13
97 #define WCCP2_ASSIGN_MAP 14
98 #define WCCP2_COMMAND_EXTENSION 15
102 /** \interface WCCPv2_Protocol
103 * Sect 5.5 WCCP Message Header
105 struct wccp2_message_header_t
{
108 #define WCCP2_VERSION 0x200
112 static struct wccp2_message_header_t wccp2_here_i_am_header
;
115 #define WCCP2_HERE_I_AM 10
116 #define WCCP2_I_SEE_YOU 11
117 #define WCCP2_REDIRECT_ASSIGN 12
118 #define WCCP2_REMOVAL_QUERY 13
121 /** \interface WCCPv2_Protocol
122 * Sect 5.6.1 Security Info Component
124 * Basic security Header. Matches "no security" case exactly.
126 struct wccp2_security_none_t
{
127 uint16_t security_type
;
128 uint16_t security_length
;
129 uint32_t security_option
;
132 /* security options */
133 #define WCCP2_NO_SECURITY 0
134 #define WCCP2_MD5_SECURITY 1
137 /** \interface WCCPv2_Protocol
138 * Sect 5.6.1 Security Info Component
140 * Extended security section. Matches "MD5 security" type exactly.
141 * Including the security header.
143 struct wccp2_security_md5_t
{
144 uint16_t security_type
;
145 uint16_t security_length
;
146 uint32_t security_option
;
147 uint8_t security_implementation
[WCCP2_MD5_SECURITY_LEN
];
150 /* Service info struct */
152 /** \interface WCCPv2_Protocol
153 * Sect 5.6.2 Service Info Component
155 struct wccp2_service_info_t
{
156 uint16_t service_type
;
157 uint16_t service_length
;
160 uint8_t service_priority
;
161 uint8_t service_protocol
;
162 uint32_t service_flags
;
173 #define WCCP2_SERVICE_STANDARD 0
174 #define WCCP2_SERVICE_DYNAMIC 1
177 #define WCCP2_SERVICE_ID_HTTP 0x00
180 #define WCCP2_SERVICE_SRC_IP_HASH 0x1
181 #define WCCP2_SERVICE_DST_IP_HASH 0x2
182 #define WCCP2_SERVICE_SRC_PORT_HASH 0x4
183 #define WCCP2_SERVICE_DST_PORT_HASH 0x8
184 #define WCCP2_SERVICE_PORTS_DEFINED 0x10
185 #define WCCP2_SERVICE_PORTS_SOURCE 0x20
186 #define WCCP2_SERVICE_SRC_IP_ALT_HASH 0x100
187 #define WCCP2_SERVICE_DST_IP_ALT_HASH 0x200
188 #define WCCP2_SERVICE_SRC_PORT_ALT_HASH 0x400
189 #define WCCP2_SERVICE_DST_PORT_ALT_HASH 0x800
192 /* TODO the following structures need to be re-defined for correct full operation.
193 wccp2_cache_identity_element needs to be merged as a sub-struct of
194 wccp2_identity_info_t (identity_type); which frees up the identifty info
195 structures so mask_assigment_data_element can become variable length
196 and cope with multiple fail-over caches hanging off one router.
199 /** \interface WCCPv2_Protocol
200 * Sect 5.7.2 Web-Cache Identity Element
202 struct wccp2_cache_identity_info_t
{
204 uint16_t hash_revision
;
206 //#define WCCP2_HASH_ASSIGNMENT_DATA 0x0
208 /* 5.7.2 Hash Assignment Data Element */
209 char buckets
[32]; /* Draft indicates 8x 32-bit buckets but it's just a mask so doesn't matter how we define. */
214 /** \interface WCCPv2_Protocol
215 * Sect 5.6.4 Web-Cache Identity Info Component
217 struct wccp2_identity_info_t
{
218 uint16_t cache_identity_type
;
219 uint16_t cache_identity_length
;
221 struct wccp2_cache_identity_info_t cache_identity
;
224 static struct wccp2_identity_info_t wccp2_identity_info
;
226 /** \interface WCCPv2_Protocol
227 * Sect 5.7.7 Mask Element
229 struct wccp2_mask_element_t
{
230 uint32_t source_ip_mask
;
231 uint32_t dest_ip_mask
;
232 uint16_t source_port_mask
;
233 uint16_t dest_port_mask
;
234 uint32_t number_values
;
238 /** \interface WCCPv2_Protocol
239 * Sect 5.7.2 Web-Cache Identity Element
241 struct wccp2_cache_mask_identity_info_t
{
243 uint16_t hash_revision
;
245 #define WCCP2_MASK_ASSIGNMENT_DATA (0x2)
247 /* Sect 5.7.2 Mask Assignment Data Element
249 * NP: draft specifies a variable-length set of keys here.
250 * the following fields only matche the special case Squid sends outbound (single-cache).
252 uint32_t mask_element_count
;
254 /* Sect 5.7.6 Mask/Value Set Element */
255 /* special case: single mask element. no values. */
256 struct wccp2_mask_element_t mask
;
258 /* Sect 5.7.2 Mask Assignment Data Element */
263 /** \interface WCCPv2_Protocol
264 * Sect 5.6.4 Web-Cache Identity Info Component
266 struct wccp2_mask_identity_info_t
{
267 uint16_t cache_identity_type
;
268 uint16_t cache_identity_length
;
270 struct wccp2_cache_mask_identity_info_t cache_identity
;
273 static struct wccp2_mask_identity_info_t wccp2_mask_identity_info
;
275 /** \interface WCCPv2_Protocol
276 * Sect 5.6.5 Router View Info Component
277 * Sect 5.6.6 Web Cache View Info Component
279 * first three fields. (shared by both view components)
281 struct wccp2_cache_view_header_t
{
282 uint16_t cache_view_type
;
283 uint16_t cache_view_length
;
284 uint32_t cache_view_version
;
287 static struct wccp2_cache_view_header_t wccp2_cache_view_header
;
289 /// \interface WCCPv2_Protocol
290 /* NP: special-case 5.6.5 or 5.6.6 * View Info when no routers or caches are advertised? */
291 struct wccp2_cache_view_info_t
{
292 uint32_t num_routers
;
296 static struct wccp2_cache_view_info_t wccp2_cache_view_info
;
298 /** \interface WCCPv2_Protocol
299 * Sect 5.7.1 Router ID Element
301 struct wccp2_router_id_element_t
{
302 struct in_addr router_address
;
303 uint32_t received_id
;
306 static struct wccp2_router_id_element_t wccp2_router_id_element
;
308 /** \interface WCCPv2_Protocol
309 * Sect 5.6.9 Capabilities Info Component
311 struct wccp2_capability_info_header_t
{
312 uint16_t capability_info_type
;
313 uint16_t capability_info_length
;
314 /* dynamic length capabilities list */
317 static struct wccp2_capability_info_header_t wccp2_capability_info_header
;
319 /** \interface WCCPv2_Protocol
320 * 5.7.5 Capability Element
322 struct wccp2_capability_element_t
{
323 uint16_t capability_type
;
324 uint16_t capability_length
;
325 uint32_t capability_value
;
327 static struct wccp2_capability_element_t wccp2_capability_element
;
329 /* capability types */
330 #define WCCP2_CAPABILITY_FORWARDING_METHOD 0x01
331 #define WCCP2_CAPABILITY_ASSIGNMENT_METHOD 0x02
332 #define WCCP2_CAPABILITY_RETURN_METHOD 0x03
334 /* capability values */
335 #define WCCP2_METHOD_GRE 0x00000001
336 #define WCCP2_METHOD_L2 0x00000002
337 /* when type=WCCP2_CAPABILITY_FORWARDING_METHOD */
338 #define WCCP2_FORWARDING_METHOD_GRE WCCP2_METHOD_GRE
339 #define WCCP2_FORWARDING_METHOD_L2 WCCP2_METHOD_L2
340 /* when type=WCCP2_CAPABILITY_ASSIGNMENT_METHOD */
341 #define WCCP2_ASSIGNMENT_METHOD_HASH 0x00000001
342 #define WCCP2_ASSIGNMENT_METHOD_MASK 0x00000002
343 /* when type=WCCP2_CAPABILITY_RETURN_METHOD */
344 #define WCCP2_PACKET_RETURN_METHOD_GRE WCCP2_METHOD_GRE
345 #define WCCP2_PACKET_RETURN_METHOD_L2 WCCP2_METHOD_L2
349 /** \interface WCCPv2_Protocol
350 * 5.7.8 Value Element
352 struct wccp2_value_element_t
{
353 uint32_t source_ip_value
;
354 uint32_t dest_ip_value
;
355 uint16_t source_port_value
;
356 uint16_t dest_port_value
;
358 struct in_addr cache_ip
;
361 /* RECEIVED PACKET STRUCTURE */
363 /** \interface WCCPv2_Protocol
364 * 5.2 'I See You' Message
366 struct wccp2_i_see_you_t
{
370 char data
[WCCP_RESPONSE_SIZE
];
373 static struct wccp2_i_see_you_t wccp2_i_see_you
;
375 /** \interface WCCPv2_Protocol
376 * 5.7.4 Router Assignment Element
378 struct wccp2_router_assign_element_t
{
379 struct in_addr router_address
;
380 uint32_t received_id
;
381 uint32_t change_number
;
384 /* Router identity struct */
386 /** \interface WCCPv2_Protocol
387 * 5.6.3 Router Identity Info Component (partial)
389 struct router_identity_info_t
{
391 struct wccp2_item_header_t header
;
393 struct wccp2_router_id_element_t router_id_element
;
395 struct in_addr router_address
;
396 uint32_t number_caches
;
397 /* dynamic list of cache IP addresses */
400 /* The received packet for a mask assignment is unusual */
402 /** \interface WCCPv2_Protocol
403 * Sect 5.7.7 Mask Element ???
404 * see code below. apparently the supposed IP address at position num1 can be equal to 3.
406 struct cache_mask_info_t
{
413 /** \interface WCCPv2_Protocol
414 * 5.7.3 Assignment Key Element
416 struct assignment_key_t
{
417 struct in_addr master_ip
;
418 uint32_t master_number
;
421 /** \interface WCCPv2_Protocol
422 * 5.6.5 Router View Info Component (first three fields)
424 struct router_view_t
{
425 struct wccp2_item_header_t header
;
426 uint32_t change_number
;
427 struct assignment_key_t assignment_key
;
428 /* dynamic lists of routers and caches elided */
431 /* Lists used to keep track of caches, routers and services */
433 /// \interface WCCPv2_Protocol
434 struct wccp2_cache_list_t
{
436 struct in_addr cache_ip
;
440 struct wccp2_cache_list_t
*next
;
443 /// \interface WCCPv2_Protocol
444 struct wccp2_router_list_t
{
446 struct wccp2_router_id_element_t
*info
;
448 struct in_addr local_ip
;
450 struct in_addr router_sendto_address
;
451 uint32_t member_change
;
454 struct wccp2_cache_list_t cache_list_head
;
456 struct wccp2_router_list_t
*next
;
459 static int wccp2_numrouters
;
461 /// \interface WCCPv2_Protocol
462 struct wccp2_service_list_t
{
464 struct wccp2_service_info_t info
;
465 uint32_t num_routers
;
467 struct wccp2_router_list_t router_list_head
;
471 char *wccp2_identity_info_ptr
;
473 struct wccp2_security_md5_t
*security_info
;
475 struct wccp2_service_info_t
*service_info
;
476 char wccp_packet
[WCCP_RESPONSE_SIZE
];
477 size_t wccp_packet_size
;
479 struct wccp2_service_list_t
*next
;
480 char wccp_password
[WCCP2_PASSWORD_LEN
+ 1]; /* hold the trailing C-string NUL */
481 uint32_t wccp2_security_type
;
484 static struct wccp2_service_list_t
*wccp2_service_list_head
= NULL
;
486 int empty_portlist
[WCCP2_NUMPORTS
] = {0, 0, 0, 0, 0, 0, 0, 0};
488 /* END WCCP V2 PROTOCL TYPES DEFINITION */
490 void wccp2_add_service_list(int service
, int service_id
, int service_priority
,
491 int service_proto
, int service_flags
, int ports
[], int security_type
, char *password
);
492 static void wccp2SortCacheList(struct wccp2_cache_list_t
*head
);
495 * The functions used during startup:
497 * wccp2ConnectionOpen
498 * wccp2ConnectionClose
502 wccp2InitServices(void)
504 debugs(80, 5, "wccp2InitServices: called");
508 wccp2_update_service(struct wccp2_service_list_t
*srv
, int service
,
509 int service_id
, int service_priority
, int service_proto
, int service_flags
,
512 /* XXX check what needs to be wrapped in htons()! */
513 srv
->info
.service
= service
;
514 srv
->info
.service_id
= service_id
;
515 srv
->info
.service_priority
= service_priority
;
516 srv
->info
.service_protocol
= service_proto
;
517 srv
->info
.service_flags
= htonl(service_flags
);
518 srv
->info
.port0
= htons(ports
[0]);
519 srv
->info
.port1
= htons(ports
[1]);
520 srv
->info
.port2
= htons(ports
[2]);
521 srv
->info
.port3
= htons(ports
[3]);
522 srv
->info
.port4
= htons(ports
[4]);
523 srv
->info
.port5
= htons(ports
[5]);
524 srv
->info
.port6
= htons(ports
[6]);
525 srv
->info
.port7
= htons(ports
[7]);
529 wccp2_add_service_list(int service
, int service_id
, int service_priority
,
530 int service_proto
, int service_flags
, int ports
[], int security_type
,
534 struct wccp2_service_list_t
*wccp2_service_list_ptr
;
536 wccp2_service_list_ptr
= (wccp2_service_list_t
*) xcalloc(1, sizeof(struct wccp2_service_list_t
));
538 debugs(80, 5, "wccp2_add_service_list: added service id " << service_id
);
540 /* XXX check what needs to be wrapped in htons()! */
541 wccp2_service_list_ptr
->info
.service_type
= htons(WCCP2_SERVICE_INFO
);
543 wccp2_service_list_ptr
->info
.service_length
= htons(sizeof(struct wccp2_service_info_t
) - 4);
544 wccp2_service_list_ptr
->change_num
= 0;
545 wccp2_update_service(wccp2_service_list_ptr
, service
, service_id
,
546 service_priority
, service_proto
, service_flags
, ports
);
547 wccp2_service_list_ptr
->wccp2_security_type
= security_type
;
548 memset(wccp2_service_list_ptr
->wccp_password
, 0, WCCP2_PASSWORD_LEN
+ 1);
549 strncpy(wccp2_service_list_ptr
->wccp_password
, password
, WCCP2_PASSWORD_LEN
);
550 /* add to linked list - XXX this should use the Squid dlink* routines! */
551 wccp2_service_list_ptr
->next
= wccp2_service_list_head
;
552 wccp2_service_list_head
= wccp2_service_list_ptr
;
555 static struct wccp2_service_list_t
*
556 wccp2_get_service_by_id(int service
, int service_id
) {
558 struct wccp2_service_list_t
*p
;
560 p
= wccp2_service_list_head
;
563 if (p
->info
.service
== service
&& p
->info
.service_id
== service_id
) {
574 * Update the md5 security header, if possible
576 * Returns: 1 if we set it, 0 if not (eg, no security section, or non-md5)
579 wccp2_update_md5_security(char *password
, char *ptr
, char *packet
, int len
)
581 uint8_t md5_digest
[16];
582 char pwd
[WCCP2_PASSWORD_LEN
];
585 struct wccp2_security_md5_t
*ws
;
587 debugs(80, 5, "wccp2_update_md5_security: called");
589 /* The password field, for the MD5 hash, needs to be 8 bytes and NUL padded. */
590 memset(pwd
, 0, sizeof(pwd
));
591 strncpy(pwd
, password
, sizeof(pwd
));
593 ws
= (struct wccp2_security_md5_t
*) ptr
;
594 assert(ntohs(ws
->security_type
) == WCCP2_SECURITY_INFO
);
595 /* Its the security part */
597 if (ntohl(ws
->security_option
) != WCCP2_MD5_SECURITY
) {
598 debugs(80, 5, "wccp2_update_md5_security: this service ain't md5'ing, abort");
602 /* And now its the MD5 section! */
603 /* According to the draft, the MD5 security hash is the combination of
604 * the 8-octet password (padded w/ NUL bytes) and the entire WCCP packet,
605 * including the WCCP message header. The WCCP security implementation
606 * area should be zero'ed before calculating the MD5 hash.
608 /* XXX eventually we should be able to kill md5_digest and blit it directly in */
609 memset(ws
->security_implementation
, 0, sizeof(ws
->security_implementation
));
613 SquidMD5Update(&M
, pwd
, 8);
615 SquidMD5Update(&M
, packet
, len
);
617 SquidMD5Final(md5_digest
, &M
);
619 memcpy(ws
->security_implementation
, md5_digest
, sizeof(md5_digest
));
627 * Check the given WCCP2 packet against the given password.
631 wccp2_check_security(struct wccp2_service_list_t
*srv
, char *security
, char *packet
, int len
)
634 struct wccp2_security_md5_t
*ws
= (struct wccp2_security_md5_t
*) security
;
635 uint8_t md5_digest
[16], md5_challenge
[16];
636 char pwd
[WCCP2_PASSWORD_LEN
];
639 /* Make sure the security type matches what we expect */
641 if (ntohl(ws
->security_option
) != srv
->wccp2_security_type
) {
642 debugs(80, 1, "wccp2_check_security: received packet has the wrong security option");
646 if (srv
->wccp2_security_type
== WCCP2_NO_SECURITY
) {
650 if (srv
->wccp2_security_type
!= WCCP2_MD5_SECURITY
) {
651 debugs(80, 1, "wccp2_check_security: invalid security option");
655 /* If execution makes it here then we have an MD5 security */
657 /* The password field, for the MD5 hash, needs to be 8 bytes and NUL padded. */
658 memset(pwd
, 0, sizeof(pwd
));
660 strncpy(pwd
, srv
->wccp_password
, sizeof(pwd
));
662 /* Take a copy of the challenge: we need to NUL it before comparing */
663 memcpy(md5_challenge
, ws
->security_implementation
, 16);
665 memset(ws
->security_implementation
, 0, sizeof(ws
->security_implementation
));
669 SquidMD5Update(&M
, pwd
, 8);
671 SquidMD5Update(&M
, packet
, len
);
673 SquidMD5Final(md5_digest
, &M
);
675 return (memcmp(md5_digest
, md5_challenge
, 16) == 0);
684 uint32_t service_flags
;
686 struct wccp2_service_list_t
*service_list_ptr
;
688 struct wccp2_router_list_t
*router_list_ptr
;
690 struct wccp2_security_md5_t wccp2_security_md5
;
692 debugs(80, 5, "wccp2Init: Called");
694 if (wccp2_connected
== 1)
697 wccp2_numrouters
= 0;
699 /* Calculate the number of routers configured in the config file */
700 for (s
= Config
.Wccp2
.router
; s
; s
= s
->next
) {
701 if (!s
->s
.IsAnyAddr()) {
702 /* Increment the counter */
707 if (wccp2_numrouters
== 0) {
711 /* Initialise the list of services */
714 service_list_ptr
= wccp2_service_list_head
;
716 while (service_list_ptr
!= NULL
) {
717 /* Set up our list pointers */
718 router_list_ptr
= &service_list_ptr
->router_list_head
;
720 /* start the wccp header */
721 wccp2_here_i_am_header
.type
= htonl(WCCP2_HERE_I_AM
);
722 wccp2_here_i_am_header
.version
= htons(WCCP2_VERSION
);
723 wccp2_here_i_am_header
.length
= 0;
724 ptr
= service_list_ptr
->wccp_packet
+ sizeof(wccp2_here_i_am_header
);
726 /* add the security section */
727 /* XXX this is ugly */
729 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
730 wccp2_security_md5
.security_option
= htonl(WCCP2_MD5_SECURITY
);
732 wccp2_security_md5
.security_length
= htons(sizeof(struct wccp2_security_md5_t
) - 4);
733 } else if (service_list_ptr
->wccp2_security_type
== WCCP2_NO_SECURITY
) {
734 wccp2_security_md5
.security_option
= htonl(WCCP2_NO_SECURITY
);
735 /* XXX I hate magic length numbers! */
736 wccp2_security_md5
.security_length
= htons(4);
738 fatalf("Bad WCCP2 security type\n");
741 wccp2_here_i_am_header
.length
+= ntohs(wccp2_security_md5
.security_length
) + 4;
742 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
743 wccp2_security_md5
.security_type
= htons(WCCP2_SECURITY_INFO
);
745 service_list_ptr
->security_info
= (struct wccp2_security_md5_t
*) ptr
;
747 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
749 xmemcpy(ptr
, &wccp2_security_md5
, sizeof(struct wccp2_security_md5_t
));
751 ptr
+= sizeof(struct wccp2_security_md5_t
);
753 /* assume NONE, and XXX I hate magic length numbers */
754 xmemcpy(ptr
, &wccp2_security_md5
, 8);
758 /* Add the service info section */
760 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_service_info_t
);
762 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
764 xmemcpy(ptr
, &service_list_ptr
->info
, sizeof(struct wccp2_service_info_t
));
766 service_list_ptr
->service_info
= (struct wccp2_service_info_t
*) ptr
;
768 ptr
+= sizeof(struct wccp2_service_info_t
);
770 /* Add the cache identity section */
772 switch (Config
.Wccp2
.assignment_method
) {
774 case WCCP2_ASSIGNMENT_METHOD_HASH
:
776 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_identity_info_t
);
777 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
778 wccp2_identity_info
.cache_identity_type
= htons(WCCP2_WC_ID_INFO
);
779 wccp2_identity_info
.cache_identity_length
= htons(sizeof(wccp2_identity_info
.cache_identity
));
780 memset(&wccp2_identity_info
.cache_identity
.addr
, '\0', sizeof(struct in_addr
));
781 memset(&wccp2_identity_info
.cache_identity
.hash_revision
, '\0', sizeof(wccp2_identity_info
.cache_identity
.hash_revision
));
782 memset(&wccp2_identity_info
.cache_identity
.bits
, '\0', sizeof(wccp2_identity_info
.cache_identity
.bits
));
783 memset(&wccp2_identity_info
.cache_identity
.buckets
, '\0', sizeof(wccp2_identity_info
.cache_identity
.buckets
));
784 wccp2_identity_info
.cache_identity
.weight
= htons(Config
.Wccp2
.weight
);
785 memset(&wccp2_identity_info
.cache_identity
.status
, '\0', sizeof(wccp2_identity_info
.cache_identity
.status
));
787 xmemcpy(ptr
, &wccp2_identity_info
, sizeof(struct wccp2_identity_info_t
));
788 service_list_ptr
->wccp2_identity_info_ptr
= ptr
;
790 ptr
+= sizeof(struct wccp2_identity_info_t
);
793 case WCCP2_ASSIGNMENT_METHOD_MASK
:
795 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_mask_identity_info_t
);
796 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
797 wccp2_mask_identity_info
.cache_identity_type
= htons(WCCP2_WC_ID_INFO
);
798 wccp2_mask_identity_info
.cache_identity_length
= htons(sizeof(wccp2_mask_identity_info
.cache_identity
));
799 memset(&wccp2_mask_identity_info
.cache_identity
.addr
, '\0', sizeof(struct in_addr
));
800 wccp2_mask_identity_info
.cache_identity
.bits
= htons(WCCP2_MASK_ASSIGNMENT_DATA
);
801 wccp2_mask_identity_info
.cache_identity
.mask_element_count
= htonl(1);
802 service_flags
= ntohl(service_list_ptr
->service_info
->service_flags
);
804 memset(&wccp2_mask_identity_info
.cache_identity
.mask
, 0, sizeof(struct wccp2_mask_element_t
));
806 if ((service_flags
& WCCP2_SERVICE_SRC_IP_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
)) {
807 wccp2_mask_identity_info
.cache_identity
.mask
.source_ip_mask
= htonl(0x00001741);
808 } else if ((service_list_ptr
->info
.service
== WCCP2_SERVICE_STANDARD
) || (service_flags
& WCCP2_SERVICE_DST_IP_HASH
) || (service_flags
& WCCP2_SERVICE_DST_IP_ALT_HASH
)) {
809 wccp2_mask_identity_info
.cache_identity
.mask
.dest_ip_mask
= htonl(0x00001741);
810 } else if ((service_flags
& WCCP2_SERVICE_SRC_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
)) {
811 wccp2_mask_identity_info
.cache_identity
.mask
.source_port_mask
= htons(0x1741);
812 } else if ((service_flags
& WCCP2_SERVICE_DST_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
)) {
813 wccp2_mask_identity_info
.cache_identity
.mask
.dest_port_mask
= htons(0x1741);
815 fatalf("Unknown service hash method\n");
818 wccp2_mask_identity_info
.cache_identity
.weight
= 0;
819 wccp2_mask_identity_info
.cache_identity
.status
= 0;
821 xmemcpy(ptr
, &wccp2_mask_identity_info
, sizeof(struct wccp2_mask_identity_info_t
));
822 service_list_ptr
->wccp2_identity_info_ptr
= ptr
;
824 ptr
+= sizeof(struct wccp2_mask_identity_info_t
);
828 fatalf("Unknown Wccp2 assignment method\n");
831 /* Add the cache view section */
832 wccp2_here_i_am_header
.length
+= sizeof(wccp2_cache_view_header
);
834 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
836 wccp2_cache_view_header
.cache_view_type
= htons(WCCP2_WC_VIEW_INFO
);
838 wccp2_cache_view_header
.cache_view_length
= htons(sizeof(wccp2_cache_view_header
) - 4 +
839 sizeof(wccp2_cache_view_info
) + (wccp2_numrouters
* sizeof(wccp2_router_id_element
)));
841 wccp2_cache_view_header
.cache_view_version
= htonl(1);
843 xmemcpy(ptr
, &wccp2_cache_view_header
, sizeof(wccp2_cache_view_header
));
845 ptr
+= sizeof(wccp2_cache_view_header
);
847 /* Add the number of routers to the packet */
848 wccp2_here_i_am_header
.length
+= sizeof(service_list_ptr
->num_routers
);
850 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
852 service_list_ptr
->num_routers
= htonl(wccp2_numrouters
);
854 xmemcpy(ptr
, &service_list_ptr
->num_routers
, sizeof(service_list_ptr
->num_routers
));
856 ptr
+= sizeof(service_list_ptr
->num_routers
);
858 /* Add each router. Keep this functionality here to make sure the received_id can be updated in the packet */
859 for (s
= Config
.Wccp2
.router
; s
; s
= s
->next
) {
860 if (!s
->s
.IsAnyAddr()) {
862 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_router_id_element_t
);
863 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
865 /* Add a pointer to the router list for this router */
867 router_list_ptr
->info
= (struct wccp2_router_id_element_t
*) ptr
;
868 s
->s
.GetInAddr(router_list_ptr
->info
->router_address
);
869 router_list_ptr
->info
->received_id
= htonl(0);
870 s
->s
.GetInAddr(router_list_ptr
->router_sendto_address
);
871 router_list_ptr
->member_change
= htonl(0);
873 /* Build the next struct */
875 router_list_ptr
->next
= (wccp2_router_list_t
*) xcalloc(1, sizeof(struct wccp2_router_list_t
));
877 /* update the pointer */
878 router_list_ptr
= router_list_ptr
->next
;
879 router_list_ptr
->next
= NULL
;
881 /* no need to copy memory - we've just set the values directly in the packet above */
883 ptr
+= sizeof(struct wccp2_router_id_element_t
);
887 /* Add the number of caches (0) */
888 wccp2_here_i_am_header
.length
+= sizeof(wccp2_cache_view_info
.num_caches
);
890 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
892 wccp2_cache_view_info
.num_caches
= htonl(0);
894 xmemcpy(ptr
, &wccp2_cache_view_info
.num_caches
, sizeof(wccp2_cache_view_info
.num_caches
));
896 ptr
+= sizeof(wccp2_cache_view_info
.num_caches
);
898 /* Add the extra capability header */
899 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_info_header
);
901 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
903 wccp2_capability_info_header
.capability_info_type
= htons(WCCP2_CAPABILITY_INFO
);
905 wccp2_capability_info_header
.capability_info_length
= htons(3 * sizeof(wccp2_capability_element
));
907 xmemcpy(ptr
, &wccp2_capability_info_header
, sizeof(wccp2_capability_info_header
));
909 ptr
+= sizeof(wccp2_capability_info_header
);
911 /* Add the forwarding method */
912 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_element
);
914 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
916 wccp2_capability_element
.capability_type
= htons(WCCP2_CAPABILITY_FORWARDING_METHOD
);
918 wccp2_capability_element
.capability_length
= htons(sizeof(wccp2_capability_element
.capability_value
));
920 wccp2_capability_element
.capability_value
= htonl(Config
.Wccp2
.forwarding_method
);
922 xmemcpy(ptr
, &wccp2_capability_element
, sizeof(wccp2_capability_element
));
924 ptr
+= sizeof(wccp2_capability_element
);
926 /* Add the assignment method */
927 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_element
);
929 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
931 wccp2_capability_element
.capability_type
= htons(WCCP2_CAPABILITY_ASSIGNMENT_METHOD
);
933 wccp2_capability_element
.capability_length
= htons(sizeof(wccp2_capability_element
.capability_value
));
935 wccp2_capability_element
.capability_value
= htonl(Config
.Wccp2
.assignment_method
);
937 xmemcpy(ptr
, &wccp2_capability_element
, sizeof(wccp2_capability_element
));
939 ptr
+= sizeof(wccp2_capability_element
);
941 /* Add the return method */
942 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_element
);
944 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
946 wccp2_capability_element
.capability_type
= htons(WCCP2_CAPABILITY_RETURN_METHOD
);
948 wccp2_capability_element
.capability_length
= htons(sizeof(wccp2_capability_element
.capability_value
));
950 wccp2_capability_element
.capability_value
= htonl(Config
.Wccp2
.return_method
);
952 xmemcpy(ptr
, &wccp2_capability_element
, sizeof(wccp2_capability_element
));
954 ptr
+= sizeof(wccp2_capability_element
);
956 /* Finally, fix the total length to network order, and copy to the appropriate memory blob */
957 wccp2_here_i_am_header
.length
= htons(wccp2_here_i_am_header
.length
);
959 memcpy(&service_list_ptr
->wccp_packet
, &wccp2_here_i_am_header
, sizeof(wccp2_here_i_am_header
));
961 service_list_ptr
->wccp_packet_size
= ntohs(wccp2_here_i_am_header
.length
) + sizeof(wccp2_here_i_am_header
);
963 /* Add the event if everything initialised correctly */
964 debugs(80,3,"wccp2Init: scheduled 'HERE_I_AM' message to " << wccp2_numrouters
<< "routers.");
965 if (wccp2_numrouters
) {
966 if (!eventFind(wccp2HereIam
, NULL
)) {
967 eventAdd("wccp2HereIam", wccp2HereIam
, NULL
, 1, 1);
969 debugs(80,3,"wccp2Init: skip duplicate 'HERE_I_AM'.");
972 service_list_ptr
= service_list_ptr
->next
;
977 wccp2ConnectionOpen(void)
979 struct sockaddr_in router
, local
, null
;
980 socklen_t local_len
, router_len
;
982 struct wccp2_service_list_t
*service_list_ptr
;
984 struct wccp2_router_list_t
*router_list_ptr
;
986 debugs(80, 5, "wccp2ConnectionOpen: Called");
988 if (wccp2_numrouters
== 0 || !wccp2_service_list_head
) {
989 debugs(80, 2, "WCCPv2 Disabled.");
993 if ( !Config
.Wccp2
.address
.SetIPv4() ) {
994 debugs(80, 0, "WCCPv2 Disabled. " << Config
.Wccp2
.address
<< " is not an IPv4 address.");
998 Config
.Wccp2
.address
.SetPort(WCCP_PORT
);
999 theWccp2Connection
= comm_open_listener(SOCK_DGRAM
,
1001 Config
.Wccp2
.address
,
1005 if (theWccp2Connection
< 0)
1006 fatal("Cannot open WCCP Port");
1008 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1010 int i
= IP_PMTUDISC_DONT
;
1011 setsockopt(theWccp2Connection
, SOL_IP
, IP_MTU_DISCOVER
, &i
, sizeof i
);
1015 commSetSelect(theWccp2Connection
,
1021 debugs(80, 1, "Accepting WCCPv2 messages on port " << WCCP_PORT
<< ", FD " << theWccp2Connection
<< ".");
1022 debugs(80, 1, "Initialising all WCCPv2 lists");
1024 /* Initialise all routers on all services */
1025 memset(&null
, 0, sizeof(null
));
1027 null
.sin_family
= AF_UNSPEC
;
1029 service_list_ptr
= wccp2_service_list_head
;
1031 while (service_list_ptr
!= NULL
) {
1032 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1033 router_len
= sizeof(router
);
1034 memset(&router
, '\0', router_len
);
1035 router
.sin_family
= AF_INET
;
1036 router
.sin_port
= htons(WCCP_PORT
);
1037 router
.sin_addr
= router_list_ptr
->router_sendto_address
;
1039 if (connect(theWccp2Connection
, (struct sockaddr
*) &router
, router_len
))
1040 fatal("Unable to connect WCCP out socket");
1042 local_len
= sizeof(local
);
1044 memset(&local
, '\0', local_len
);
1046 if (getsockname(theWccp2Connection
, (struct sockaddr
*) &local
, &local_len
))
1047 fatal("Unable to getsockname on WCCP out socket");
1049 router_list_ptr
->local_ip
= local
.sin_addr
;
1051 /* Disconnect the sending socket. Note: FreeBSD returns error
1052 * but disconnects anyway so we have to just assume it worked
1054 if (wccp2_numrouters
> 1)
1055 connect(theWccp2Connection
, (struct sockaddr
*) &null
, router_len
);
1058 service_list_ptr
= service_list_ptr
->next
;
1061 wccp2_connected
= 1;
1065 wccp2ConnectionClose(void)
1068 struct wccp2_service_list_t
*service_list_ptr
;
1070 struct wccp2_service_list_t
*service_list_ptr_next
;
1072 struct wccp2_router_list_t
*router_list_ptr
;
1074 struct wccp2_router_list_t
*router_list_next
;
1076 struct wccp2_cache_list_t
*cache_list_ptr
;
1078 struct wccp2_cache_list_t
*cache_list_ptr_next
;
1080 if (wccp2_connected
== 0) {
1084 if (theWccp2Connection
> -1) {
1085 debugs(80, 1, "FD " << theWccp2Connection
<< " Closing WCCPv2 socket");
1086 comm_close(theWccp2Connection
);
1087 theWccp2Connection
= -1;
1090 /* for each router on each service send a packet */
1091 service_list_ptr
= wccp2_service_list_head
;
1093 while (service_list_ptr
!= NULL
) {
1094 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
!= NULL
; router_list_ptr
= router_list_next
) {
1095 for (cache_list_ptr
= &router_list_ptr
->cache_list_head
; cache_list_ptr
; cache_list_ptr
= cache_list_ptr_next
) {
1096 cache_list_ptr_next
= cache_list_ptr
->next
;
1098 if (cache_list_ptr
!= &router_list_ptr
->cache_list_head
) {
1099 xfree(cache_list_ptr
);
1102 memset(cache_list_ptr
, '\0', sizeof(struct wccp2_cache_list_t
));
1106 router_list_next
= router_list_ptr
->next
;
1108 if (router_list_ptr
!= &service_list_ptr
->router_list_head
) {
1109 xfree(router_list_ptr
);
1112 memset(router_list_ptr
, '\0', sizeof(struct wccp2_router_list_t
));
1116 service_list_ptr_next
= service_list_ptr
->next
;
1117 xfree(service_list_ptr
);
1118 service_list_ptr
= service_list_ptr_next
;
1121 wccp2_service_list_head
= NULL
;
1122 eventDelete(wccp2HereIam
, NULL
);
1123 eventDelete(wccp2AssignBuckets
, NULL
);
1124 eventDelete(wccp2HereIam
, NULL
);
1125 wccp2_connected
= 0;
1129 * Functions for handling the requests.
1133 * Accept the UDP packet
1136 wccp2HandleUdp(int sock
, void *not_used
)
1139 struct wccp2_service_list_t
*service_list_ptr
;
1141 struct wccp2_router_list_t
*router_list_ptr
;
1143 struct wccp2_cache_list_t
*cache_list_ptr
;
1145 struct wccp2_cache_list_t
*cache_list_ptr_next
;
1147 /* These structs form the parts of the packet */
1149 struct wccp2_item_header_t
*header
= NULL
;
1151 struct wccp2_security_none_t
*security_info
= NULL
;
1153 struct wccp2_service_info_t
*service_info
= NULL
;
1155 struct router_identity_info_t
*router_identity_info
= NULL
;
1157 struct router_view_t
*router_view_header
= NULL
;
1159 struct wccp2_cache_mask_identity_info_t
*cache_mask_identity
= NULL
;
1161 struct cache_mask_info_t
*cache_mask_info
= NULL
;
1163 struct wccp2_cache_identity_info_t
*cache_identity
= NULL
;
1165 struct wccp2_capability_info_header_t
*router_capability_header
= NULL
;
1167 struct wccp2_capability_element_t
*router_capability_element
;
1169 struct sockaddr_in from
;
1171 struct in_addr cache_address
;
1173 short int data_length
, offset
;
1178 debugs(80, 6, "wccp2HandleUdp: Called.");
1180 commSetSelect(sock
, COMM_SELECT_READ
, wccp2HandleUdp
, NULL
, 0);
1182 /* FIXME INET6 : drop conversion boundary */
1183 Ip::Address from_tmp
;
1185 len
= comm_udp_recvfrom(sock
,
1190 /* FIXME INET6 : drop conversion boundary */
1191 from_tmp
.GetSockAddr(from
);
1196 if (ntohs(wccp2_i_see_you
.version
) != WCCP2_VERSION
)
1199 if (ntohl(wccp2_i_see_you
.type
) != WCCP2_I_SEE_YOU
)
1202 debugs(80, 3, "Incoming WCCPv2 I_SEE_YOU length " << ntohs(wccp2_i_see_you
.length
) << ".");
1204 /* Record the total data length */
1205 data_length
= ntohs(wccp2_i_see_you
.length
);
1209 if (data_length
> len
) {
1210 debugs(80, 1, "ERROR: Malformed WCCPv2 packet claiming it's bigger than received data");
1214 /* Go through the data structure */
1215 while (data_length
> offset
) {
1217 char *data
= wccp2_i_see_you
.data
;
1219 header
= (struct wccp2_item_header_t
*) &data
[offset
];
1221 switch (ntohs(header
->type
)) {
1223 case WCCP2_SECURITY_INFO
:
1225 if (security_info
!= NULL
) {
1226 debugs(80, 1, "Duplicate security definition");
1230 security_info
= (struct wccp2_security_none_t
*) &wccp2_i_see_you
.data
[offset
];
1233 case WCCP2_SERVICE_INFO
:
1235 if (service_info
!= NULL
) {
1236 debugs(80, 1, "Duplicate service_info definition");
1240 service_info
= (struct wccp2_service_info_t
*) &wccp2_i_see_you
.data
[offset
];
1243 case WCCP2_ROUTER_ID_INFO
:
1245 if (router_identity_info
!= NULL
) {
1246 debugs(80, 1, "Duplicate router_identity_info definition");
1250 router_identity_info
= (struct router_identity_info_t
*) &wccp2_i_see_you
.data
[offset
];
1253 case WCCP2_RTR_VIEW_INFO
:
1255 if (router_view_header
!= NULL
) {
1256 debugs(80, 1, "Duplicate router_view definition");
1260 router_view_header
= (struct router_view_t
*) &wccp2_i_see_you
.data
[offset
];
1263 case WCCP2_CAPABILITY_INFO
:
1265 if (router_capability_header
!= NULL
) {
1266 debugs(80, 1, "Duplicate router_capability definition");
1270 router_capability_header
= (struct wccp2_capability_info_header_t
*) &wccp2_i_see_you
.data
[offset
];
1273 /* Nothing to do for the types below */
1275 case WCCP2_ASSIGN_MAP
:
1279 debugs(80, 1, "Unknown record type in WCCPv2 Packet (" << ntohs(header
->type
) << ").");
1282 offset
+= sizeof(struct wccp2_item_header_t
);
1283 offset
+= ntohs(header
->length
);
1285 if (offset
> data_length
) {
1286 debugs(80, 1, "Error: WCCPv2 packet tried to tell us there is data beyond the end of the packet");
1291 if ((security_info
== NULL
) || (service_info
== NULL
) || (router_identity_info
== NULL
) || (router_view_header
== NULL
)) {
1292 debugs(80, 1, "Incomplete WCCPv2 Packet");
1296 debugs(80, 5, "Complete packet received");
1298 /* Check that the service in the packet is configured on this router */
1299 service_list_ptr
= wccp2_service_list_head
;
1301 while (service_list_ptr
!= NULL
) {
1302 if (service_info
->service_id
== service_list_ptr
->service_info
->service_id
) {
1306 service_list_ptr
= service_list_ptr
->next
;
1309 if (service_list_ptr
== NULL
) {
1310 debugs(80, 1, "WCCPv2 Unknown service received from router (" << service_info
->service_id
<< ")");
1314 if (ntohl(security_info
->security_option
) != ntohl(service_list_ptr
->security_info
->security_option
)) {
1315 debugs(80, 1, "Invalid security option in WCCPv2 Packet (" << ntohl(security_info
->security_option
) << " vs " << ntohl(service_list_ptr
->security_info
->security_option
) << ").");
1319 if (!wccp2_check_security(service_list_ptr
, (char *) security_info
, (char *) &wccp2_i_see_you
, len
)) {
1320 debugs(80, 1, "Received WCCPv2 Packet failed authentication");
1324 /* Check that the router address is configured on this router */
1325 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1326 if (router_list_ptr
->router_sendto_address
.s_addr
== from
.sin_addr
.s_addr
)
1330 if (router_list_ptr
->next
== NULL
) {
1331 debugs(80, 1, "WCCPv2 Packet received from unknown router");
1335 /* Set the router id */
1336 router_list_ptr
->info
->router_address
= router_identity_info
->router_id_element
.router_address
;
1338 /* Increment the received id in the packet */
1339 if (ntohl(router_list_ptr
->info
->received_id
) != ntohl(router_identity_info
->router_id_element
.received_id
)) {
1340 debugs(80, 3, "Incoming WCCP2_I_SEE_YOU Received ID old=" << ntohl(router_list_ptr
->info
->received_id
) << " new=" << ntohl(router_identity_info
->router_id_element
.received_id
) << ".");
1341 router_list_ptr
->info
->received_id
= router_identity_info
->router_id_element
.received_id
;
1344 /* TODO: check return/forwarding methods */
1345 if (router_capability_header
== NULL
) {
1346 if ((Config
.Wccp2
.return_method
!= WCCP2_PACKET_RETURN_METHOD_GRE
) || (Config
.Wccp2
.forwarding_method
!= WCCP2_FORWARDING_METHOD_GRE
)) {
1347 debugs(80, 1, "wccp2HandleUdp: fatal error - A WCCP router does not support the forwarding method specified, only GRE supported");
1348 wccp2ConnectionClose();
1353 char *end
= ((char *) router_capability_header
) + sizeof(*router_capability_header
) + ntohs(router_capability_header
->capability_info_length
) - sizeof(struct wccp2_capability_info_header_t
);
1355 router_capability_element
= (struct wccp2_capability_element_t
*) (((char *) router_capability_header
) + sizeof(*router_capability_header
));
1357 while ((char *) router_capability_element
<= end
) {
1359 switch (ntohs(router_capability_element
->capability_type
)) {
1361 case WCCP2_CAPABILITY_FORWARDING_METHOD
:
1363 if (!(ntohl(router_capability_element
->capability_value
) & Config
.Wccp2
.forwarding_method
)) {
1364 debugs(80, 1, "wccp2HandleUdp: fatal error - A WCCP router has specified a different forwarding method " << ntohl(router_capability_element
->capability_value
) << ", expected " << Config
.Wccp2
.forwarding_method
);
1365 wccp2ConnectionClose();
1371 case WCCP2_CAPABILITY_ASSIGNMENT_METHOD
:
1373 if (!(ntohl(router_capability_element
->capability_value
) & Config
.Wccp2
.assignment_method
)) {
1374 debugs(80, 1, "wccp2HandleUdp: fatal error - A WCCP router has specified a different assignment method " << ntohl(router_capability_element
->capability_value
) << ", expected "<< Config
.Wccp2
.assignment_method
);
1375 wccp2ConnectionClose();
1381 case WCCP2_CAPABILITY_RETURN_METHOD
:
1383 if (!(ntohl(router_capability_element
->capability_value
) & Config
.Wccp2
.return_method
)) {
1384 debugs(80, 1, "wccp2HandleUdp: fatal error - A WCCP router has specified a different return method " << ntohl(router_capability_element
->capability_value
) << ", expected " << Config
.Wccp2
.return_method
);
1385 wccp2ConnectionClose();
1392 debugs(80, 1, "Unknown capability type in WCCPv2 Packet (" << ntohs(router_capability_element
->capability_type
) << ").");
1395 router_capability_element
= (struct wccp2_capability_element_t
*) (((char *) router_capability_element
) + sizeof(struct wccp2_item_header_t
) + ntohs(router_capability_element
->capability_length
));
1399 debugs(80, 5, "Cleaning out cache list");
1400 /* clean out the old cache list */
1402 for (cache_list_ptr
= &router_list_ptr
->cache_list_head
; cache_list_ptr
; cache_list_ptr
= cache_list_ptr_next
) {
1403 cache_list_ptr_next
= cache_list_ptr
->next
;
1405 if (cache_list_ptr
!= &router_list_ptr
->cache_list_head
) {
1406 xfree(cache_list_ptr
);
1410 router_list_ptr
->num_caches
= htonl(0);
1413 /* Check to see if we're the master cache and update the cache list */
1415 service_list_ptr
->lowest_ip
= 1;
1416 cache_list_ptr
= &router_list_ptr
->cache_list_head
;
1418 /* to find the list of caches, we start at the end of the router view header */
1420 ptr
= (char *) (router_view_header
) + sizeof(struct router_view_t
);
1422 /* Then we read the number of routers */
1423 memcpy(&tmp
, ptr
, sizeof(tmp
));
1425 /* skip the number plus all the ip's */
1427 ptr
+= sizeof(tmp
) + (ntohl(tmp
) * sizeof(struct in_addr
));
1429 /* Then read the number of caches */
1430 memcpy(&tmp
, ptr
, sizeof(tmp
));
1433 if (ntohl(tmp
) != 0) {
1434 /* search through the list of received-from ip addresses */
1436 for (num_caches
= 0; num_caches
< (int) ntohl(tmp
); num_caches
++) {
1437 /* Get a copy of the ip */
1438 memset(&cache_address
, 0, sizeof(cache_address
)); // Make GCC happy
1440 switch (Config
.Wccp2
.assignment_method
) {
1442 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1444 cache_identity
= (struct wccp2_cache_identity_info_t
*) ptr
;
1446 ptr
+= sizeof(struct wccp2_cache_identity_info_t
);
1448 memcpy(&cache_address
, &cache_identity
->addr
, sizeof(struct in_addr
));
1450 cache_list_ptr
->weight
= ntohs(cache_identity
->weight
);
1453 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1455 cache_mask_info
= (struct cache_mask_info_t
*) ptr
;
1457 /* The mask assignment has an undocumented variable length entry here */
1459 if (ntohl(cache_mask_info
->num1
) == 3) {
1461 cache_mask_identity
= (struct wccp2_cache_mask_identity_info_t
*) ptr
;
1463 ptr
+= sizeof(struct wccp2_cache_mask_identity_info_t
);
1465 memcpy(&cache_address
, &cache_mask_identity
->addr
, sizeof(struct in_addr
));
1468 ptr
+= sizeof(struct cache_mask_info_t
);
1470 memcpy(&cache_address
, &cache_mask_info
->addr
, sizeof(struct in_addr
));
1473 cache_list_ptr
->weight
= 0;
1477 fatalf("Unknown Wccp2 assignment method\n");
1480 /* Update the cache list */
1481 cache_list_ptr
->cache_ip
= cache_address
;
1483 cache_list_ptr
->next
= (wccp2_cache_list_t
*) xcalloc(1, sizeof(struct wccp2_cache_list_t
));
1485 cache_list_ptr
= cache_list_ptr
->next
;
1487 cache_list_ptr
->next
= NULL
;
1489 debugs (80, 5, "checking cache list: (" << std::hex
<< cache_address
.s_addr
<< ":" << router_list_ptr
->local_ip
.s_addr
<< ")");
1491 /* Check to see if it's the master, or us */
1493 if (cache_address
.s_addr
== router_list_ptr
->local_ip
.s_addr
) {
1497 if (cache_address
.s_addr
< router_list_ptr
->local_ip
.s_addr
) {
1498 service_list_ptr
->lowest_ip
= 0;
1502 debugs(80, 5, "Adding ourselves as the only cache");
1504 /* Update the cache list */
1505 cache_list_ptr
->cache_ip
= router_list_ptr
->local_ip
;
1507 cache_list_ptr
->next
= (wccp2_cache_list_t
*) xcalloc(1, sizeof(struct wccp2_cache_list_t
));
1508 cache_list_ptr
= cache_list_ptr
->next
;
1509 cache_list_ptr
->next
= NULL
;
1511 service_list_ptr
->lowest_ip
= 1;
1516 wccp2SortCacheList(&router_list_ptr
->cache_list_head
);
1518 router_list_ptr
->num_caches
= htonl(num_caches
);
1520 if ((found
== 1) && (service_list_ptr
->lowest_ip
== 1)) {
1521 if (ntohl(router_view_header
->change_number
) != router_list_ptr
->member_change
) {
1522 debugs(80, 4, "Change detected - queueing up new assignment");
1523 router_list_ptr
->member_change
= ntohl(router_view_header
->change_number
);
1524 eventDelete(wccp2AssignBuckets
, NULL
);
1525 eventAdd("wccp2AssignBuckets", wccp2AssignBuckets
, NULL
, 15.0, 1);
1527 debugs(80, 5, "Change not detected (" << ntohl(router_view_header
->change_number
) << " = " << router_list_ptr
->member_change
<< ")");
1530 eventDelete(wccp2AssignBuckets
, NULL
);
1531 debugs(80, 5, "I am not the lowest ip cache - not assigning buckets");
1536 wccp2HereIam(void *voidnotused
)
1539 struct wccp2_service_list_t
*service_list_ptr
;
1541 struct wccp2_router_list_t
*router_list_ptr
;
1543 struct wccp2_identity_info_t
*wccp2_identity_info_ptr
;
1545 struct wccp2_mask_identity_info_t
*wccp2_mask_identity_info_ptr
;
1549 debugs(80, 6, "wccp2HereIam: Called");
1551 if (wccp2_connected
== 0) {
1552 debugs(80, 1, "wccp2HereIam: wccp2 socket closed. Shutting down WCCP2");
1556 /* Wait if store dirs are rebuilding */
1557 if (StoreController::store_dirs_rebuilding
&& Config
.Wccp2
.rebuildwait
) {
1558 eventAdd("wccp2HereIam", wccp2HereIam
, NULL
, 1.0, 1);
1562 router
.SetPort(WCCP_PORT
);
1564 /* for each router on each service send a packet */
1565 service_list_ptr
= wccp2_service_list_head
;
1567 while (service_list_ptr
!= NULL
) {
1568 debugs(80, 5, "wccp2HereIam: sending to service id " << service_list_ptr
->info
.service_id
);
1570 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1571 router
= router_list_ptr
->router_sendto_address
;
1573 /* Set the cache id (ip) */
1575 switch (Config
.Wccp2
.assignment_method
) {
1577 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1579 wccp2_identity_info_ptr
= (struct wccp2_identity_info_t
*) service_list_ptr
->wccp2_identity_info_ptr
;
1580 wccp2_identity_info_ptr
->cache_identity
.addr
= router_list_ptr
->local_ip
;
1583 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1585 wccp2_mask_identity_info_ptr
= (struct wccp2_mask_identity_info_t
*) service_list_ptr
->wccp2_identity_info_ptr
;
1586 wccp2_mask_identity_info_ptr
->cache_identity
.addr
= router_list_ptr
->local_ip
;
1590 fatalf("Unknown Wccp2 assignment method\n");
1593 /* Security update, if needed */
1595 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
1596 wccp2_update_md5_security(service_list_ptr
->wccp_password
, (char *) service_list_ptr
->security_info
, service_list_ptr
->wccp_packet
, service_list_ptr
->wccp_packet_size
);
1599 debugs(80, 3, "Sending HereIam packet size " << service_list_ptr
->wccp_packet_size
);
1600 /* Send the packet */
1602 if (wccp2_numrouters
> 1) {
1603 comm_udp_sendto(theWccp2Connection
,
1605 &service_list_ptr
->wccp_packet
,
1606 service_list_ptr
->wccp_packet_size
);
1608 send(theWccp2Connection
,
1609 &service_list_ptr
->wccp_packet
,
1610 service_list_ptr
->wccp_packet_size
,
1615 service_list_ptr
= service_list_ptr
->next
;
1618 eventAdd("wccp2HereIam", wccp2HereIam
, NULL
, 10.0, 1);
1622 wccp2AssignBuckets(void *voidnotused
)
1625 struct wccp2_service_list_t
*service_list_ptr
;
1627 struct wccp2_router_list_t
*router_list_ptr
;
1629 struct wccp2_cache_list_t
*cache_list_ptr
;
1630 char wccp_packet
[WCCP_RESPONSE_SIZE
];
1631 short int offset
, saved_offset
, assignment_offset
, alt_assignment_offset
;
1633 struct sockaddr_in router
;
1636 uint32_t service_flags
;
1637 u_short port
= WCCP_PORT
;
1639 /* Packet segments */
1641 struct wccp2_message_header_t
*main_header
;
1643 struct wccp2_security_md5_t
*security
= NULL
;
1644 /* service from service struct */
1646 struct wccp2_item_header_t
*assignment_header
;
1648 struct wccp2_item_header_t
*alt_assignment_type_header
= NULL
;
1650 struct assignment_key_t
*assignment_key
;
1651 /* number of routers */
1653 struct wccp2_router_assign_element_t
*router_assign
;
1654 /* number of caches */
1656 struct in_addr
*cache_address
;
1657 /* Alternative assignement mask/values */
1660 struct wccp2_mask_element_t
*mask_element
;
1662 struct wccp2_value_element_t
*value_element
;
1663 int valuecounter
, value
;
1666 assignment_offset
= alt_assignment_offset
= 0;
1668 router_len
= sizeof(router
);
1669 memset(&router
, '\0', router_len
);
1670 router
.sin_family
= AF_INET
;
1671 router
.sin_port
= htons(port
);
1673 /* Start main header - fill in length later */
1676 main_header
= (struct wccp2_message_header_t
*) &wccp_packet
[offset
];
1677 main_header
->type
= htonl(WCCP2_REDIRECT_ASSIGN
);
1678 main_header
->version
= htons(WCCP2_VERSION
);
1680 debugs(80, 2, "Running wccp2AssignBuckets");
1681 service_list_ptr
= wccp2_service_list_head
;
1683 while (service_list_ptr
!= NULL
) {
1684 /* If we're not the lowest, we don't need to worry */
1686 if (service_list_ptr
->lowest_ip
== 0) {
1688 service_list_ptr
= service_list_ptr
->next
;
1692 /* reset the offset */
1694 offset
= sizeof(struct wccp2_message_header_t
);
1696 /* build packet header from hereIam packet */
1698 /* XXX this should be made more generic! */
1699 /* XXX and I hate magic numbers! */
1700 switch (service_list_ptr
->wccp2_security_type
) {
1702 case WCCP2_NO_SECURITY
:
1704 security
= (struct wccp2_security_md5_t
*) &wccp_packet
[offset
];
1705 memcpy(security
, service_list_ptr
->security_info
, 8);
1709 case WCCP2_MD5_SECURITY
:
1711 security
= (struct wccp2_security_md5_t
*) &wccp_packet
[offset
];
1713 memcpy(security
, service_list_ptr
->security_info
, sizeof(struct wccp2_security_md5_t
));
1715 offset
+= sizeof(struct wccp2_security_md5_t
);
1719 fatalf("Unknown Wccp2 security type\n");
1724 memcpy(&wccp_packet
[offset
], service_list_ptr
->service_info
, sizeof(struct wccp2_service_info_t
));
1726 offset
+= sizeof(struct wccp2_service_info_t
);
1728 /* assignment header - fill in length later */
1730 assignment_header
= (struct wccp2_item_header_t
*) &wccp_packet
[offset
];
1732 switch (Config
.Wccp2
.assignment_method
) {
1734 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1735 assignment_header
->type
= htons(WCCP2_REDIRECT_ASSIGNMENT
);
1737 offset
+= sizeof(struct wccp2_item_header_t
);
1738 assignment_offset
= offset
;
1741 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1742 assignment_header
->type
= htons(WCCP2_ALT_ASSIGNMENT
);
1744 offset
+= sizeof(struct wccp2_item_header_t
);
1745 assignment_offset
= offset
;
1747 /* The alternative assignment has an extra header, fill in length later */
1749 alt_assignment_type_header
= (struct wccp2_item_header_t
*) &wccp_packet
[offset
];
1750 alt_assignment_type_header
->type
= htons(WCCP2_MASK_ASSIGNMENT
);
1752 offset
+= sizeof(struct wccp2_item_header_t
);
1753 alt_assignment_offset
= offset
;
1758 fatalf("Unknown Wccp2 assignment method\n");
1761 /* Assignment key - fill in master ip later */
1763 assignment_key
= (struct assignment_key_t
*) &wccp_packet
[offset
];
1765 assignment_key
->master_number
= htonl(++service_list_ptr
->change_num
);
1767 offset
+= sizeof(struct assignment_key_t
);
1769 /* Number of routers */
1770 xmemcpy(&wccp_packet
[offset
], &service_list_ptr
->num_routers
, sizeof(service_list_ptr
->num_routers
));
1772 offset
+= sizeof(service_list_ptr
->num_routers
);
1774 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1778 router_assign
= (struct wccp2_router_assign_element_t
*) &wccp_packet
[offset
];
1779 router_assign
->router_address
= router_list_ptr
->info
->router_address
;
1780 router_assign
->received_id
= router_list_ptr
->info
->received_id
;
1781 router_assign
->change_number
= htonl(router_list_ptr
->member_change
);
1783 offset
+= sizeof(struct wccp2_router_assign_element_t
);
1786 saved_offset
= offset
;
1788 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1789 unsigned long *weight
= (unsigned long *)xcalloc(sizeof(*weight
), ntohl(router_list_ptr
->num_caches
));
1790 unsigned long total_weight
= 0;
1791 int num_caches
= ntohl(router_list_ptr
->num_caches
);
1793 offset
= saved_offset
;
1795 switch (Config
.Wccp2
.assignment_method
) {
1797 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1798 /* Number of caches */
1799 xmemcpy(&wccp_packet
[offset
], &router_list_ptr
->num_caches
, sizeof(router_list_ptr
->num_caches
));
1800 offset
+= sizeof(router_list_ptr
->num_caches
);
1805 for (cache
= 0, cache_list_ptr
= &router_list_ptr
->cache_list_head
; cache_list_ptr
->next
; cache_list_ptr
= cache_list_ptr
->next
, cache
++) {
1808 cache_address
= (struct in_addr
*) &wccp_packet
[offset
];
1810 xmemcpy(cache_address
, &cache_list_ptr
->cache_ip
, sizeof(struct in_addr
));
1811 total_weight
+= cache_list_ptr
->weight
<< 12;
1812 weight
[cache
] = cache_list_ptr
->weight
<< 12;
1814 offset
+= sizeof(struct in_addr
);
1819 buckets
= (char *) &wccp_packet
[offset
];
1821 memset(buckets
, '\0', WCCP_BUCKETS
);
1823 if (num_caches
!= 0) {
1824 if (total_weight
== 0) {
1825 for (bucket_counter
= 0; bucket_counter
< WCCP_BUCKETS
; bucket_counter
++) {
1826 buckets
[bucket_counter
] = (char) (bucket_counter
% num_caches
);
1829 unsigned long *assigned
= (unsigned long *)xcalloc(sizeof(*assigned
), num_caches
);
1830 unsigned long done
= 0;
1832 unsigned long per_bucket
= total_weight
/ WCCP_BUCKETS
;
1834 for (bucket_counter
= 0; bucket_counter
< WCCP_BUCKETS
; bucket_counter
++) {
1838 for (n
= num_caches
; n
; n
--) {
1841 if (cache
>= num_caches
)
1844 if (!weight
[cache
]) {
1849 if (assigned
[cache
] <= done
)
1853 buckets
[bucket_counter
] = (char) cache
;
1854 step
= per_bucket
* total_weight
/ weight
[cache
];
1855 assigned
[cache
] += step
;
1859 safe_free(assigned
);
1863 offset
+= (WCCP_BUCKETS
* sizeof(char));
1867 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1868 num_maskval
= htonl(1);
1869 xmemcpy(&wccp_packet
[offset
], &num_maskval
, sizeof(int));
1870 offset
+= sizeof(int);
1872 mask_element
= (struct wccp2_mask_element_t
*) &wccp_packet
[offset
];
1873 service_flags
= ntohl(service_list_ptr
->service_info
->service_flags
);
1875 if ((service_flags
& WCCP2_SERVICE_SRC_IP_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
)) {
1876 mask_element
->source_ip_mask
= htonl(0x00001741);
1877 mask_element
->dest_ip_mask
= 0;
1878 mask_element
->source_port_mask
= 0;
1879 mask_element
->dest_port_mask
= 0;
1880 } else if ((service_list_ptr
->info
.service
== WCCP2_SERVICE_STANDARD
) || (service_flags
& WCCP2_SERVICE_DST_IP_HASH
) || (service_flags
& WCCP2_SERVICE_DST_IP_ALT_HASH
)) {
1881 mask_element
->source_ip_mask
= 0;
1882 mask_element
->dest_ip_mask
= htonl(0x00001741);
1883 mask_element
->source_port_mask
= 0;
1884 mask_element
->dest_port_mask
= 0;
1885 } else if ((service_flags
& WCCP2_SERVICE_SRC_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
)) {
1886 mask_element
->source_ip_mask
= 0;
1887 mask_element
->dest_ip_mask
= 0;
1888 mask_element
->source_port_mask
= htons(0x1741);
1889 mask_element
->dest_port_mask
= 0;
1890 } else if ((service_flags
& WCCP2_SERVICE_DST_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
)) {
1891 mask_element
->source_ip_mask
= 0;
1892 mask_element
->dest_ip_mask
= 0;
1893 mask_element
->source_port_mask
= 0;
1894 mask_element
->dest_port_mask
= htons(0x1741);
1896 fatalf("Unknown service hash method\n");
1899 mask_element
->number_values
= htonl(64);
1901 offset
+= sizeof(struct wccp2_mask_element_t
);
1903 cache_list_ptr
= &router_list_ptr
->cache_list_head
;
1906 for (valuecounter
= 0; valuecounter
< 64; valuecounter
++) {
1908 value_element
= (struct wccp2_value_element_t
*) &wccp_packet
[offset
];
1910 /* Update the value according the the "correct" formula */
1912 for (; (value
& 0x1741) != value
; value
++) {
1913 assert(value
<= 0x1741);
1916 if ((service_flags
& WCCP2_SERVICE_SRC_IP_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
)) {
1917 value_element
->source_ip_value
= htonl(value
);
1918 value_element
->dest_ip_value
= 0;
1919 value_element
->source_port_value
= 0;
1920 value_element
->dest_port_value
= 0;
1921 } else if ((service_list_ptr
->info
.service
== WCCP2_SERVICE_STANDARD
) || (service_flags
& WCCP2_SERVICE_DST_IP_HASH
) || (service_flags
& WCCP2_SERVICE_DST_IP_ALT_HASH
)) {
1922 value_element
->source_ip_value
= 0;
1923 value_element
->dest_ip_value
= htonl(value
);
1924 value_element
->source_port_value
= 0;
1925 value_element
->dest_port_value
= 0;
1926 } else if ((service_flags
& WCCP2_SERVICE_SRC_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
)) {
1927 value_element
->source_ip_value
= 0;
1928 value_element
->dest_ip_value
= 0;
1929 value_element
->source_port_value
= htons(value
);
1930 value_element
->dest_port_value
= 0;
1931 } else if ((service_flags
& WCCP2_SERVICE_DST_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
)) {
1932 value_element
->source_ip_value
= 0;
1933 value_element
->dest_ip_value
= 0;
1934 value_element
->source_port_value
= 0;
1935 value_element
->dest_port_value
= htons(value
);
1937 fatalf("Unknown service hash method\n");
1940 value_element
->cache_ip
= cache_list_ptr
->cache_ip
;
1942 offset
+= sizeof(struct wccp2_value_element_t
);
1945 /* Assign the next value to the next cache */
1947 if ((cache_list_ptr
->next
) && (cache_list_ptr
->next
->next
))
1948 cache_list_ptr
= cache_list_ptr
->next
;
1950 cache_list_ptr
= &router_list_ptr
->cache_list_head
;
1953 /* Fill in length */
1954 alt_assignment_type_header
->length
= htons(offset
- alt_assignment_offset
);
1959 fatalf("Unknown Wccp2 assignment method\n");
1962 /* Fill in length */
1964 assignment_header
->length
= htons(offset
- assignment_offset
);
1966 /* Fill in assignment key */
1967 assignment_key
->master_ip
= router_list_ptr
->local_ip
;
1971 main_header
->length
= htons(offset
- sizeof(struct wccp2_message_header_t
));
1973 /* set the destination address */
1974 router
.sin_addr
= router_list_ptr
->router_sendto_address
;
1976 /* Security update, if needed */
1978 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
1979 wccp2_update_md5_security(service_list_ptr
->wccp_password
, (char *) security
, wccp_packet
, offset
);
1982 if (ntohl(router_list_ptr
->num_caches
)) {
1985 if (wccp2_numrouters
> 1) {
1986 /* FIXME INET6 : drop temp conversion */
1987 Ip::Address
tmp_rtr(router
);
1988 comm_udp_sendto(theWccp2Connection
,
1993 send(theWccp2Connection
,
2001 service_list_ptr
= service_list_ptr
->next
;
2007 * Configuration option parsing code
2011 * Parse wccp2_return_method and wccp2_forwarding_method options
2012 * they can be '1' aka 'gre' or '2' aka 'l2'
2013 * repesenting the integer numeric of the same.
2016 parse_wccp2_method(int *method
)
2020 /* Snarf the method */
2021 if ((t
= strtok(NULL
, w_space
)) == NULL
) {
2022 debugs(80, DBG_CRITICAL
, "wccp2_*_method: missing setting.");
2026 /* update configuration if its valid */
2027 if (strcmp(t
, "gre") == 0 || strcmp(t
, "1") == 0) {
2028 *method
= WCCP2_METHOD_GRE
;
2029 } else if (strcmp(t
, "l2") == 0 || strcmp(t
, "2") == 0) {
2030 *method
= WCCP2_METHOD_L2
;
2032 debugs(80, DBG_CRITICAL
, "wccp2_*_method: unknown setting, got " << t
);
2038 dump_wccp2_method(StoreEntry
* e
, const char *label
, int v
)
2041 case WCCP2_METHOD_GRE
:
2042 storeAppendPrintf(e
, "%s gre\n", label
);
2044 case WCCP2_METHOD_L2
:
2045 storeAppendPrintf(e
, "%s l2\n", label
);
2048 debugs(80, DBG_CRITICAL
, "FATAL: WCCPv2 configured method (" << v
<< ") is not valid.");
2054 free_wccp2_method(int *v
)
2058 * Parse wccp2_assignment_method option
2059 * they can be '1' aka 'hash' or '2' aka 'mask'
2060 * repesenting the integer numeric of the same.
2063 parse_wccp2_amethod(int *method
)
2067 /* Snarf the method */
2068 if ((t
= strtok(NULL
, w_space
)) == NULL
) {
2069 debugs(80, DBG_CRITICAL
, "wccp2_assignment_method: missing setting.");
2073 /* update configuration if its valid */
2074 if (strcmp(t
, "hash") == 0 || strcmp(t
, "1") == 0) {
2075 *method
= WCCP2_ASSIGNMENT_METHOD_HASH
;
2076 } else if (strcmp(t
, "mask") == 0 || strcmp(t
, "2") == 0) {
2077 *method
= WCCP2_ASSIGNMENT_METHOD_MASK
;
2079 debugs(80, DBG_CRITICAL
, "wccp2_assignment_method: unknown setting, got " << t
);
2085 dump_wccp2_amethod(StoreEntry
* e
, const char *label
, int v
)
2088 case WCCP2_ASSIGNMENT_METHOD_HASH
:
2089 storeAppendPrintf(e
, "%s hash\n", label
);
2091 case WCCP2_ASSIGNMENT_METHOD_MASK
:
2092 storeAppendPrintf(e
, "%s mask\n", label
);
2095 debugs(80, DBG_CRITICAL
, "FATAL: WCCPv2 configured " << label
<< " (" << v
<< ") is not valid.");
2101 free_wccp2_amethod(int *v
)
2107 * wccp2_service {standard|dynamic} {id} (password=password)
2110 parse_wccp2_service(void *v
)
2115 int security_type
= WCCP2_NO_SECURITY
;
2116 char wccp_password
[WCCP2_PASSWORD_LEN
+ 1];
2118 if (wccp2_connected
== 1) {
2119 debugs(80, 1, "WCCPv2: Somehow reparsing the configuration without having shut down WCCP! Try reloading squid again.");
2123 /* Snarf the type */
2124 if ((t
= strtok(NULL
, w_space
)) == NULL
) {
2125 debugs(80, 0, "wccp2ParseServiceInfo: missing service info type (standard|dynamic)");
2129 if (strcmp(t
, "standard") == 0) {
2130 service
= WCCP2_SERVICE_STANDARD
;
2131 } else if (strcmp(t
, "dynamic") == 0) {
2132 service
= WCCP2_SERVICE_DYNAMIC
;
2134 debugs(80, 0, "wccp2ParseServiceInfo: bad service info type (expected standard|dynamic, got " << t
<< ")");
2139 service_id
= GetInteger();
2141 if (service_id
< 0 || service_id
> 255) {
2142 debugs(80, 0, "wccp2ParseServiceInfo: service info id " << service_id
<< " is out of range (0..255)");
2146 memset(wccp_password
, 0, sizeof(wccp_password
));
2147 /* Handle password, if any */
2149 if ((t
= strtok(NULL
, w_space
)) != NULL
) {
2150 if (strncmp(t
, "password=", 9) == 0) {
2151 security_type
= WCCP2_MD5_SECURITY
;
2152 strncpy(wccp_password
, t
+ 9, WCCP2_PASSWORD_LEN
);
2156 /* Create a placeholder service record */
2157 wccp2_add_service_list(service
, service_id
, 0, 0, 0, empty_portlist
, security_type
, wccp_password
);
2161 dump_wccp2_service(StoreEntry
* e
, const char *label
, void *v
)
2164 struct wccp2_service_list_t
*srv
;
2165 srv
= wccp2_service_list_head
;
2167 while (srv
!= NULL
) {
2168 debugs(80, 3, "dump_wccp2_service: id " << srv
->info
.service_id
<< ", type " << srv
->info
.service
);
2169 storeAppendPrintf(e
, "%s %s %d", label
,
2170 (srv
->info
.service
== WCCP2_SERVICE_DYNAMIC
) ? "dynamic" : "standard",
2171 srv
->info
.service_id
);
2173 if (srv
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
2174 storeAppendPrintf(e
, " %s", srv
->wccp_password
);
2177 storeAppendPrintf(e
, "\n");
2184 free_wccp2_service(void *v
)
2188 check_null_wccp2_service(void *v
)
2190 return !wccp2_service_list_head
;
2196 * wccp2_service_info {id} stuff..
2200 * + flags=flag,flag,flag..
2201 * + proto=protocol (tcp|udp)
2202 * + ports=port,port,port (up to a max of 8)
2203 * + priority=priority (0->255)
2205 * The flags here are:
2206 * src_ip_hash, dst_ip_hash, source_port_hash, dst_port_hash, ports_defined,
2207 * ports_source, src_ip_alt_hash, dst_ip_alt_hash, src_port_alt_hash, dst_port_alt_hash
2210 parse_wccp2_service_flags(char *flags
)
2220 tmp
= xstrdup(flags
);
2223 flag
= strsep(&tmp2
, ",");
2226 if (strcmp(flag
, "src_ip_hash") == 0) {
2227 retflag
|= WCCP2_SERVICE_SRC_IP_HASH
;
2228 } else if (strcmp(flag
, "dst_ip_hash") == 0) {
2229 retflag
|= WCCP2_SERVICE_DST_IP_HASH
;
2230 } else if (strcmp(flag
, "source_port_hash") == 0) {
2231 retflag
|= WCCP2_SERVICE_SRC_PORT_HASH
;
2232 } else if (strcmp(flag
, "dst_port_hash") == 0) {
2233 retflag
|= WCCP2_SERVICE_DST_PORT_HASH
;
2234 } else if (strcmp(flag
, "ports_source") == 0) {
2235 retflag
|= WCCP2_SERVICE_PORTS_SOURCE
;
2236 } else if (strcmp(flag
, "src_ip_alt_hash") == 0) {
2237 retflag
|= WCCP2_SERVICE_SRC_IP_ALT_HASH
;
2238 } else if (strcmp(flag
, "dst_ip_alt_hash") == 0) {
2239 retflag
|= WCCP2_SERVICE_DST_IP_ALT_HASH
;
2240 } else if (strcmp(flag
, "src_port_alt_hash") == 0) {
2241 retflag
|= WCCP2_SERVICE_SRC_PORT_ALT_HASH
;
2242 } else if (strcmp(flag
, "dst_port_alt_hash") == 0) {
2243 retflag
|= WCCP2_SERVICE_DST_PORT_ALT_HASH
;
2245 fatalf("Unknown wccp2 service flag: %s\n", flag
);
2248 flag
= strsep(&tmp2
, ",");
2256 parse_wccp2_service_ports(char *options
, int portlist
[])
2260 char *tmp
, *tmp2
, *port
, *end
;
2266 tmp
= xstrdup(options
);
2269 port
= strsep(&tmp2
, ",");
2271 while (port
&& i
< WCCP2_NUMPORTS
) {
2272 p
= strtol(port
, &end
, 0);
2274 if (p
< 1 || p
> 65535) {
2275 fatalf("parse_wccp2_service_ports: port value '%s' isn't valid (1..65535)\n", port
);
2280 port
= strsep(&tmp2
, ",");
2283 if (i
== WCCP2_NUMPORTS
&& port
) {
2284 fatalf("parse_wccp2_service_ports: too many ports (maximum: 8) in list '%s'\n", options
);
2291 parse_wccp2_service_info(void *v
)
2296 int portlist
[WCCP2_NUMPORTS
];
2297 int protocol
= -1; /* IPPROTO_TCP | IPPROTO_UDP */
2299 struct wccp2_service_list_t
*srv
;
2302 if (wccp2_connected
== 1) {
2303 debugs(80, 1, "WCCPv2: Somehow reparsing the configuration without having shut down WCCP! Try reloading squid again.");
2307 debugs(80, 5, "parse_wccp2_service_info: called");
2308 memset(portlist
, 0, sizeof(portlist
));
2309 /* First argument: id */
2310 service_id
= GetInteger();
2312 if (service_id
< 0 || service_id
> 255) {
2313 debugs(80, 1, "parse_wccp2_service_info: invalid service id " << service_id
<< " (must be between 0 .. 255)");
2317 /* Next: find the (hopefully!) existing service */
2318 srv
= wccp2_get_service_by_id(WCCP2_SERVICE_DYNAMIC
, service_id
);
2321 fatalf("parse_wccp2_service_info: unknown dynamic service id %d: you need to define it using wccp2_service (and make sure you wish to configure it as a dynamic service.)\n", service_id
);
2324 /* Next: loop until we don't have any more tokens */
2325 while ((t
= strtok(NULL
, w_space
)) != NULL
) {
2326 if (strncmp(t
, "flags=", 6) == 0) {
2327 /* XXX eww, string pointer math */
2328 flags
= parse_wccp2_service_flags(t
+ 6);
2329 } else if (strncmp(t
, "ports=", 6) == 0) {
2330 parse_wccp2_service_ports(t
+ 6, portlist
);
2331 flags
|= WCCP2_SERVICE_PORTS_DEFINED
;
2332 } else if (strncmp(t
, "protocol=tcp", 12) == 0) {
2333 protocol
= IPPROTO_TCP
;
2334 } else if (strncmp(t
, "protocol=udp", 12) == 0) {
2335 protocol
= IPPROTO_UDP
;
2336 } else if (strncmp(t
, "protocol=", 9) == 0) {
2337 fatalf("parse_wccp2_service_info: id %d: unknown protocol (%s) - must be tcp or udp!\n", service_id
, t
);
2338 } else if (strncmp(t
, "priority=", 9) == 0) {
2339 priority
= strtol(t
+ 9, &end
, 0);
2341 if (priority
< 0 || priority
> 255) {
2342 fatalf("parse_wccp2_service_info: id %d: %s out of range (0..255)!\n", service_id
, t
);
2345 fatalf("parse_wccp2_service_info: id %d: unknown option '%s'\n", service_id
, t
);
2349 /* Check everything is set */
2350 if (priority
== -1) {
2351 fatalf("parse_wccp2_service_info: service %d: no priority defined (valid: 0..255)!\n", service_id
);
2354 if (protocol
== -1) {
2355 fatalf("parse_wccp2_service_info: service %d: no protocol defined (valid: tcp or udp)!\n", service_id
);
2358 if (!(flags
& WCCP2_SERVICE_PORTS_DEFINED
)) {
2359 fatalf("parse_wccp2_service_info: service %d: no ports defined!\n", service_id
);
2362 /* rightio! now we can update */
2363 wccp2_update_service(srv
, WCCP2_SERVICE_DYNAMIC
, service_id
, priority
,
2364 protocol
, flags
, portlist
);
2370 dump_wccp2_service_info(StoreEntry
* e
, const char *label
, void *v
)
2374 struct wccp2_service_list_t
*srv
;
2376 srv
= wccp2_service_list_head
;
2378 while (srv
!= NULL
) {
2379 debugs(80, 3, "dump_wccp2_service_info: id " << srv
->info
.service_id
<< " (type " << srv
->info
.service
<< ")");
2381 /* We don't need to spit out information for standard services */
2383 if (srv
->info
.service
== WCCP2_SERVICE_STANDARD
) {
2384 debugs(80, 3, "dump_wccp2_service_info: id " << srv
->info
.service_id
<< ": standard service, not dumping info");
2391 storeAppendPrintf(e
, "%s %d", label
, srv
->info
.service_id
);
2394 storeAppendPrintf(e
, " priority=%d", srv
->info
.service_priority
);
2397 flags
= ntohl(srv
->info
.service_flags
);
2401 storeAppendPrintf(e
, " flags=");
2403 if (flags
& WCCP2_SERVICE_SRC_IP_HASH
) {
2404 storeAppendPrintf(e
, "%ssrc_ip_hash", comma
? "," : "");
2408 if (flags
& WCCP2_SERVICE_DST_IP_HASH
) {
2409 storeAppendPrintf(e
, "%sdst_ip_hash", comma
? "," : "");
2413 if (flags
& WCCP2_SERVICE_SRC_PORT_HASH
) {
2414 storeAppendPrintf(e
, "%ssource_port_hash", comma
? "," : "");
2418 if (flags
& WCCP2_SERVICE_DST_PORT_HASH
) {
2419 storeAppendPrintf(e
, "%sdst_port_hash", comma
? "," : "");
2423 if (flags
& WCCP2_SERVICE_PORTS_DEFINED
) {
2424 storeAppendPrintf(e
, "%sports_defined", comma
? "," : "");
2428 if (flags
& WCCP2_SERVICE_PORTS_SOURCE
) {
2429 storeAppendPrintf(e
, "%sports_source", comma
? "," : "");
2433 if (flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
) {
2434 storeAppendPrintf(e
, "%ssrc_ip_alt_hash", comma
? "," : "");
2438 if (flags
& WCCP2_SERVICE_DST_IP_ALT_HASH
) {
2439 storeAppendPrintf(e
, "%ssrc_ip_alt_hash", comma
? "," : "");
2443 if (flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
) {
2444 storeAppendPrintf(e
, "%ssrc_port_alt_hash", comma
? "," : "");
2448 if (flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
) {
2449 storeAppendPrintf(e
, "%sdst_port_alt_hash", comma
? "," : "");
2457 if (srv
->info
.port0
!= 0) {
2458 storeAppendPrintf(e
, "%s%d", comma
? "," : " ports=", ntohs(srv
->info
.port0
));
2462 if (srv
->info
.port1
!= 0) {
2463 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port1
));
2467 if (srv
->info
.port2
!= 0) {
2468 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port2
));
2472 if (srv
->info
.port3
!= 0) {
2473 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port3
));
2477 if (srv
->info
.port4
!= 0) {
2478 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port4
));
2482 if (srv
->info
.port5
!= 0) {
2483 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port5
));
2487 if (srv
->info
.port6
!= 0) {
2488 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port6
));
2492 if (srv
->info
.port7
!= 0) {
2493 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port7
));
2498 storeAppendPrintf(e
, " protocol=%s", (srv
->info
.service_protocol
== IPPROTO_TCP
) ? "tcp" : "udp");
2500 storeAppendPrintf(e
, "\n");
2506 /* Sort the cache list by doing a "selection sort" by IP address */
2508 wccp2SortCacheList(struct wccp2_cache_list_t
*head
)
2510 struct wccp2_cache_list_t tmp
;
2511 struct wccp2_cache_list_t
*this_item
;
2512 struct wccp2_cache_list_t
*find_item
;
2513 struct wccp2_cache_list_t
*next_lowest
;
2515 /* Go through each position in the list one at a time */
2516 for (this_item
= head
; this_item
->next
; this_item
= this_item
->next
) {
2517 /* Find the item with the lowest IP */
2518 next_lowest
= this_item
;
2520 for (find_item
= this_item
; find_item
->next
; find_item
= find_item
->next
) {
2521 if (find_item
->cache_ip
.s_addr
< next_lowest
->cache_ip
.s_addr
) {
2522 next_lowest
= find_item
;
2525 /* Swap if we need to */
2526 if (next_lowest
!= this_item
) {
2527 /* First make a copy of the current item */
2528 memcpy(&tmp
, this_item
, sizeof(struct wccp2_cache_list_t
));
2530 /* Next update the pointers to maintain the linked list */
2531 tmp
.next
= next_lowest
->next
;
2532 next_lowest
->next
= this_item
->next
;
2534 /* Finally copy the updated items to their correct location */
2535 memcpy(this_item
, next_lowest
, sizeof(struct wccp2_cache_list_t
));
2536 memcpy(next_lowest
, &tmp
, sizeof(struct wccp2_cache_list_t
));
2542 free_wccp2_service_info(void *v
)
2545 #endif /* USE_WCCPv2 */