3 * $Id: wccp2.cc,v 1.20 2007/12/14 23:11:48 amosjeffries Exp $
5 * DEBUG: section 80 WCCP Support
6 * AUTHOR: Steven Wilton
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
42 #include "IPAddress.h"
47 #define WCCP_PORT 2048
48 #define WCCP_RESPONSE_SIZE 12448
49 #define WCCP_BUCKETS 256
51 static int theWccp2Connection
= -1;
52 static int wccp2_connected
= 0;
54 static PF wccp2HandleUdp
;
55 static EVH wccp2HereIam
;
56 static EVH wccp2AssignBuckets
;
59 #define WCCP2_HERE_I_AM 10
60 #define WCCP2_I_SEE_YOU 11
61 #define WCCP2_REDIRECT_ASSIGN 12
62 #define WCCP2_REMOVAL_QUERY 13
64 #define WCCP2_VERSION 0x200
66 #define WCCP2_SECURITY_INFO 0
67 #define WCCP2_NO_SECURITY 0
68 #define WCCP2_MD5_SECURITY 1
70 #define WCCP2_SERVICE_INFO 1
71 #define WCCP2_SERVICE_STANDARD 0
72 #define WCCP2_SERVICE_DYNAMIC 1
73 #define WCCP2_SERVICE_ID_HTTP 0x00
75 #define WCCP2_SERVICE_SRC_IP_HASH 0x1
76 #define WCCP2_SERVICE_DST_IP_HASH 0x2
77 #define WCCP2_SERVICE_SRC_PORT_HASH 0x4
78 #define WCCP2_SERVICE_DST_PORT_HASH 0x8
79 #define WCCP2_SERVICE_PORTS_DEFINED 0x10
80 #define WCCP2_SERVICE_PORTS_SOURCE 0x20
81 #define WCCP2_SERVICE_SRC_IP_ALT_HASH 0x100
82 #define WCCP2_SERVICE_DST_IP_ALT_HASH 0x200
83 #define WCCP2_SERVICE_SRC_PORT_ALT_HASH 0x400
84 #define WCCP2_SERVICE_DST_PORT_ALT_HASH 0x800
86 #define WCCP2_ROUTER_ID_INFO 2
88 #define WCCP2_WC_ID_INFO 3
90 #define WCCP2_RTR_VIEW_INFO 4
92 #define WCCP2_WC_VIEW_INFO 5
94 #define WCCP2_REDIRECT_ASSIGNMENT 6
96 #define WCCP2_QUERY_INFO 7
98 #define WCCP2_CAPABILITY_INFO 8
100 #define WCCP2_ALT_ASSIGNMENT 13
102 #define WCCP2_ASSIGN_MAP 14
104 #define WCCP2_COMMAND_EXTENSION 15
106 #define WCCP2_CAPABILITY_FORWARDING_METHOD 0x01
107 #define WCCP2_CAPABILITY_ASSIGNMENT_METHOD 0x02
108 #define WCCP2_CAPABILITY_RETURN_METHOD 0x03
110 #define WCCP2_FORWARDING_METHOD_GRE 0x00000001
111 #define WCCP2_FORWARDING_METHOD_L2 0x00000002
113 #define WCCP2_ASSIGNMENT_METHOD_HASH 0x00000001
114 #define WCCP2_ASSIGNMENT_METHOD_MASK 0x00000002
116 #define WCCP2_PACKET_RETURN_METHOD_GRE 0x00000001
117 #define WCCP2_PACKET_RETURN_METHOD_L2 0x00000002
119 #define WCCP2_HASH_ASSIGNMENT 0x00
120 #define WCCP2_MASK_ASSIGNMENT 0x01
122 #define WCCP2_NONE_SECURITY_LEN 0
123 #define WCCP2_MD5_SECURITY_LEN 16
126 #define WCCP2_NUMPORTS 8
127 #define WCCP2_PASSWORD_LEN 8
129 /* WCCP v2 packet header */
131 /// \interface WCCPv2 Protocol
132 struct wccp2_here_i_am_header_t
139 static struct wccp2_here_i_am_header_t wccp2_here_i_am_header
;
141 /* Security struct for the "no security" option */
143 struct wccp2_security_none_t
145 uint16_t security_type
;
146 uint16_t security_length
;
147 uint32_t security_option
;
150 /// \interface WCCPv2 Protocol
151 struct wccp2_security_md5_t
153 uint16_t security_type
;
154 uint16_t security_length
;
155 uint32_t security_option
;
156 uint8_t security_implementation
[WCCP2_MD5_SECURITY_LEN
];
159 /* Service info struct */
161 /// \interface WCCPv2 Protocol
162 struct wccp2_service_info_t
164 uint16_t service_type
;
165 uint16_t service_length
;
168 uint8_t service_priority
;
169 uint8_t service_protocol
;
170 uint32_t service_flags
;
181 /// \interface WCCPv2 Protocol
182 struct wccp2_cache_identity_info_t
185 uint16_t hash_revision
;
192 /* Web Cache identity info */
194 /// \interface WCCPv2 Protocol
195 struct wccp2_identity_info_t
197 uint16_t cache_identity_type
;
198 uint16_t cache_identity_length
;
200 struct wccp2_cache_identity_info_t cache_identity
;
203 static struct wccp2_identity_info_t wccp2_identity_info
;
205 /// \interface WCCPv2 Protocol
206 struct wccp2_cache_mask_identity_info_t
211 uint32_t source_ip_mask
;
212 uint32_t dest_ip_mask
;
213 uint16_t source_port_mask
;
214 uint16_t dest_port_mask
;
219 /* Web Cache identity info */
221 /// \interface WCCPv2 Protocol
222 struct wccp2_mask_identity_info_t
224 uint16_t cache_identity_type
;
225 uint16_t cache_identity_length
;
227 struct wccp2_cache_mask_identity_info_t cache_identity
;
230 static struct wccp2_mask_identity_info_t wccp2_mask_identity_info
;
234 /// \interface WCCPv2 Protocol
235 struct wccp2_cache_view_header_t
237 uint16_t cache_view_type
;
238 uint16_t cache_view_length
;
239 uint32_t cache_view_version
;
242 static struct wccp2_cache_view_header_t wccp2_cache_view_header
;
246 /// \interface WCCPv2 Protocol
247 struct wccp2_cache_view_info_t
249 uint32_t num_routers
;
253 static struct wccp2_cache_view_info_t wccp2_cache_view_info
;
255 /* Router ID element */
257 /// \interface WCCPv2 Protocol
258 struct wccp2_router_id_element_t
260 struct in_addr router_address
;
261 uint32_t received_id
;
264 static struct wccp2_router_id_element_t wccp2_router_id_element
;
266 /* Capability info header */
268 /// \interface WCCpv2 Protocol
269 struct wccp2_capability_info_header_t
271 uint16_t capability_info_type
;
272 uint16_t capability_info_length
;
275 static struct wccp2_capability_info_header_t wccp2_capability_info_header
;
277 /* Capability element header */
279 /// \interface WCCPv2 Protocol
280 struct wccp2_capability_element_header_t
282 uint16_t capability_type
;
283 uint16_t capability_length
;
286 /* Capability element */
288 /// \interface WCCPv2 Protocol
289 struct wccp2_capability_element_t
291 uint16_t capability_type
;
292 uint16_t capability_length
;
293 uint32_t capability_value
;
296 static struct wccp2_capability_element_t wccp2_capability_element
;
300 /// \interface WCCPv2 Protocol
301 struct wccp2_mask_element_t
303 uint32_t source_ip_mask
;
304 uint32_t dest_ip_mask
;
305 uint16_t source_port_mask
;
306 uint16_t dest_port_mask
;
307 uint32_t number_values
;
312 /// \interface WCCPv2 Protocol
313 struct wccp2_value_element_t
315 uint32_t source_ip_value
;
316 uint32_t dest_ip_value
;
317 uint16_t source_port_value
;
318 uint16_t dest_port_value
;
320 struct in_addr cache_ip
;
323 /* RECEIVED PACKET STRUCTURE */
325 /// \interface WCCPv2 Protocol
326 struct wccp2_i_see_you_t
331 char data
[WCCP_RESPONSE_SIZE
];
334 static struct wccp2_i_see_you_t wccp2_i_see_you
;
336 /* Router ID element */
338 /// \interface WCCPv2 Protocol
339 struct wccp2_router_assign_element_t
341 struct in_addr router_address
;
342 uint32_t received_id
;
343 uint32_t change_number
;
346 /* Generic header struct */
348 /// \interface WCCPv2 Protocol
349 struct wccp2_item_header_t
355 /* Router identity struct */
357 /// \interface WCCPv2 Protocol
358 struct router_identity_info_t
361 struct wccp2_item_header_t header
;
363 struct wccp2_router_id_element_t router_id_element
;
365 struct IN_ADDR router_address
;
366 uint32_t number_caches
;
369 /* The received packet for a mask assignment is unusual */
371 /// \interface WCCPv2 Protocol
372 struct cache_mask_info_t
382 /// \interface WCCPv2 Protocol
383 struct assignment_key_t
385 struct in_addr master_ip
;
386 uint32_t master_number
;
389 /* Router view of WCCP */
391 /// \interface WCCPv2 Protocol
395 struct wccp2_item_header_t header
;
396 uint32_t change_number
;
398 struct assignment_key_t assignment_key
;
401 /* Lists used to keep track of caches, routers and services */
403 /// \interface WCCPv2 Protocol
404 struct wccp2_cache_list_t
407 struct in_addr cache_ip
;
411 struct wccp2_cache_list_t
*next
;
414 /// \interface WCCPv2 Protocol
415 struct wccp2_router_list_t
418 struct wccp2_router_id_element_t
*info
;
420 struct in_addr local_ip
;
422 struct in_addr router_sendto_address
;
423 uint32_t member_change
;
426 struct wccp2_cache_list_t cache_list_head
;
428 struct wccp2_router_list_t
*next
;
431 static int wccp2_numrouters
;
433 /// \interface WCCPv2 Protocol
434 struct wccp2_service_list_t
437 struct wccp2_service_info_t info
;
438 uint32_t num_routers
;
440 struct wccp2_router_list_t router_list_head
;
444 char *wccp2_identity_info_ptr
;
447 struct wccp2_security_md5_t
*security_info
;
449 struct wccp2_service_info_t
*service_info
;
450 char wccp_packet
[WCCP_RESPONSE_SIZE
];
451 size_t wccp_packet_size
;
453 struct wccp2_service_list_t
*next
;
454 char wccp_password
[WCCP2_PASSWORD_LEN
+ 1]; /* hold the trailing C-string NUL */
455 uint32_t wccp2_security_type
;
458 static struct wccp2_service_list_t
*wccp2_service_list_head
= NULL
;
460 int empty_portlist
[WCCP2_NUMPORTS
] =
461 {0, 0, 0, 0, 0, 0, 0, 0};
464 void wccp2_add_service_list(int service
, int service_id
, int service_priority
,
465 int service_proto
, int service_flags
, int ports
[], int security_type
, char *password
);
468 * The functions used during startup:
470 * wccp2ConnectionOpen
471 * wccp2ConnectionClose
475 wccp2InitServices(void)
477 debugs(80, 5, "wccp2InitServices: called");
482 wccp2_update_service(struct wccp2_service_list_t
*srv
, int service
,
483 int service_id
, int service_priority
, int service_proto
, int service_flags
,
486 /* XXX check what needs to be wrapped in htons()! */
487 srv
->info
.service
= service
;
488 srv
->info
.service_id
= service_id
;
489 srv
->info
.service_priority
= service_priority
;
490 srv
->info
.service_protocol
= service_proto
;
491 srv
->info
.service_flags
= htonl(service_flags
);
492 srv
->info
.port0
= htons(ports
[0]);
493 srv
->info
.port1
= htons(ports
[1]);
494 srv
->info
.port2
= htons(ports
[2]);
495 srv
->info
.port3
= htons(ports
[3]);
496 srv
->info
.port4
= htons(ports
[4]);
497 srv
->info
.port5
= htons(ports
[5]);
498 srv
->info
.port6
= htons(ports
[6]);
499 srv
->info
.port7
= htons(ports
[7]);
503 wccp2_add_service_list(int service
, int service_id
, int service_priority
,
504 int service_proto
, int service_flags
, int ports
[], int security_type
,
508 struct wccp2_service_list_t
*wccp2_service_list_ptr
;
510 wccp2_service_list_ptr
= (wccp2_service_list_t
*) xcalloc(1, sizeof(struct wccp2_service_list_t
));
512 debugs(80, 5, "wccp2_add_service_list: added service id " << service_id
);
514 /* XXX check what needs to be wrapped in htons()! */
515 wccp2_service_list_ptr
->info
.service_type
= htons(WCCP2_SERVICE_INFO
);
517 wccp2_service_list_ptr
->info
.service_length
= htons(sizeof(struct wccp2_service_info_t
) - 4);
518 wccp2_service_list_ptr
->change_num
= 0;
519 wccp2_update_service(wccp2_service_list_ptr
, service
, service_id
,
520 service_priority
, service_proto
, service_flags
, ports
);
521 wccp2_service_list_ptr
->wccp2_security_type
= security_type
;
522 memset(wccp2_service_list_ptr
->wccp_password
, 0, WCCP2_PASSWORD_LEN
+ 1);
523 strncpy(wccp2_service_list_ptr
->wccp_password
, password
, WCCP2_PASSWORD_LEN
);
524 /* add to linked list - XXX this should use the Squid dlink* routines! */
525 wccp2_service_list_ptr
->next
= wccp2_service_list_head
;
526 wccp2_service_list_head
= wccp2_service_list_ptr
;
529 static struct wccp2_service_list_t
*
530 wccp2_get_service_by_id(int service
, int service_id
)
533 struct wccp2_service_list_t
*p
;
535 p
= wccp2_service_list_head
;
539 if (p
->info
.service
== service
&& p
->info
.service_id
== service_id
) {
550 * Update the md5 security header, if possible
552 * Returns: 1 if we set it, 0 if not (eg, no security section, or non-md5)
555 wccp2_update_md5_security(char *password
, char *ptr
, char *packet
, int len
)
557 u_int8_t md5_digest
[16];
558 char pwd
[WCCP2_PASSWORD_LEN
];
561 struct wccp2_security_md5_t
*ws
;
563 debugs(80, 5, "wccp2_update_md5_security: called");
565 /* The password field, for the MD5 hash, needs to be 8 bytes and NUL padded. */
566 memset(pwd
, 0, sizeof(pwd
));
567 strncpy(pwd
, password
, sizeof(pwd
));
569 ws
= (struct wccp2_security_md5_t
*) ptr
;
570 assert(ntohs(ws
->security_type
) == WCCP2_SECURITY_INFO
);
571 /* Its the security part */
573 if (ntohl(ws
->security_option
) != WCCP2_MD5_SECURITY
) {
574 debugs(80, 5, "wccp2_update_md5_security: this service ain't md5'ing, abort");
578 /* And now its the MD5 section! */
579 /* According to the draft, the MD5 security hash is the combination of
580 * the 8-octet password (padded w/ NUL bytes) and the entire WCCP packet,
581 * including the WCCP message header. The WCCP security implementation
582 * area should be zero'ed before calculating the MD5 hash.
584 /* XXX eventually we should be able to kill md5_digest and blit it directly in */
585 memset(ws
->security_implementation
, 0, sizeof(ws
->security_implementation
));
589 SquidMD5Update(&M
, pwd
, 8);
591 SquidMD5Update(&M
, packet
, len
);
593 SquidMD5Final(md5_digest
, &M
);
595 memcpy(ws
->security_implementation
, md5_digest
, sizeof(md5_digest
));
603 * Check the given WCCP2 packet against the given password.
607 wccp2_check_security(struct wccp2_service_list_t
*srv
, char *security
, char *packet
, int len
)
610 struct wccp2_security_md5_t
*ws
= (struct wccp2_security_md5_t
*) security
;
611 u_int8_t md5_digest
[16], md5_challenge
[16];
612 char pwd
[WCCP2_PASSWORD_LEN
];
615 /* Make sure the security type matches what we expect */
617 if (ntohl(ws
->security_option
) != srv
->wccp2_security_type
)
619 debugs(80, 1, "wccp2_check_security: received packet has the wrong security option");
623 if (srv
->wccp2_security_type
== WCCP2_NO_SECURITY
)
628 if (srv
->wccp2_security_type
!= WCCP2_MD5_SECURITY
)
630 debugs(80, 1, "wccp2_check_security: invalid security option");
634 /* If execution makes it here then we have an MD5 security */
636 /* The password field, for the MD5 hash, needs to be 8 bytes and NUL padded. */
637 memset(pwd
, 0, sizeof(pwd
));
639 strncpy(pwd
, srv
->wccp_password
, sizeof(pwd
));
641 /* Take a copy of the challenge: we need to NUL it before comparing */
642 memcpy(md5_challenge
, ws
->security_implementation
, 16);
644 memset(ws
->security_implementation
, 0, sizeof(ws
->security_implementation
));
648 SquidMD5Update(&M
, pwd
, 8);
650 SquidMD5Update(&M
, packet
, len
);
652 SquidMD5Final(md5_digest
, &M
);
654 return (memcmp(md5_digest
, md5_challenge
, 16) == 0);
663 uint32_t service_flags
;
665 struct wccp2_service_list_t
*service_list_ptr
;
667 struct wccp2_router_list_t
*router_list_ptr
;
669 struct wccp2_security_md5_t wccp2_security_md5
;
671 debugs(80, 5, "wccp2Init: Called");
673 if (wccp2_connected
== 1)
676 wccp2_numrouters
= 0;
678 /* Calculate the number of routers configured in the config file */
679 for (s
= Config
.Wccp2
.router
; s
; s
= s
->next
) {
680 if (!s
->s
.IsAnyAddr()) {
681 /* Increment the counter */
686 if (wccp2_numrouters
== 0) {
690 /* Initialise the list of services */
693 service_list_ptr
= wccp2_service_list_head
;
695 while (service_list_ptr
!= NULL
) {
696 /* Set up our list pointers */
697 router_list_ptr
= &service_list_ptr
->router_list_head
;
699 /* start the wccp header */
700 wccp2_here_i_am_header
.type
= htonl(WCCP2_HERE_I_AM
);
701 wccp2_here_i_am_header
.version
= htons(WCCP2_VERSION
);
702 wccp2_here_i_am_header
.length
= 0;
703 ptr
= service_list_ptr
->wccp_packet
+ sizeof(wccp2_here_i_am_header
);
705 /* add the security section */
706 /* XXX this is ugly */
708 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
709 wccp2_security_md5
.security_option
= htonl(WCCP2_MD5_SECURITY
);
711 wccp2_security_md5
.security_length
= htons(sizeof(struct wccp2_security_md5_t
) - 4);
712 } else if (service_list_ptr
->wccp2_security_type
== WCCP2_NO_SECURITY
) {
713 wccp2_security_md5
.security_option
= htonl(WCCP2_NO_SECURITY
);
714 /* XXX I hate magic length numbers! */
715 wccp2_security_md5
.security_length
= htons(4);
717 fatalf("Bad WCCP2 security type\n");
720 wccp2_here_i_am_header
.length
+= ntohs(wccp2_security_md5
.security_length
) + 4;
721 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
722 wccp2_security_md5
.security_type
= htons(WCCP2_SECURITY_INFO
);
724 service_list_ptr
->security_info
= (struct wccp2_security_md5_t
*) ptr
;
726 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
728 xmemcpy(ptr
, &wccp2_security_md5
, sizeof(struct wccp2_security_md5_t
));
730 ptr
+= sizeof(struct wccp2_security_md5_t
);
732 /* assume NONE, and XXX I hate magic length numbers */
733 xmemcpy(ptr
, &wccp2_security_md5
, 8);
737 /* Add the service info section */
739 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_service_info_t
);
741 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
743 xmemcpy(ptr
, &service_list_ptr
->info
, sizeof(struct wccp2_service_info_t
));
745 service_list_ptr
->service_info
= (struct wccp2_service_info_t
*) ptr
;
747 ptr
+= sizeof(struct wccp2_service_info_t
);
749 /* Add the cache identity section */
751 switch (Config
.Wccp2
.assignment_method
) {
753 case WCCP2_ASSIGNMENT_METHOD_HASH
:
755 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_identity_info_t
);
756 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
757 wccp2_identity_info
.cache_identity_type
= htons(WCCP2_WC_ID_INFO
);
758 wccp2_identity_info
.cache_identity_length
= htons(sizeof(wccp2_identity_info
.cache_identity
));
759 memset(&wccp2_identity_info
.cache_identity
.addr
, '\0', sizeof(struct in_addr
));
760 memset(&wccp2_identity_info
.cache_identity
.hash_revision
, '\0', sizeof(wccp2_identity_info
.cache_identity
.hash_revision
));
761 memset(&wccp2_identity_info
.cache_identity
.bits
, '\0', sizeof(wccp2_identity_info
.cache_identity
.bits
));
762 memset(&wccp2_identity_info
.cache_identity
.buckets
, '\0', sizeof(wccp2_identity_info
.cache_identity
.buckets
));
763 wccp2_identity_info
.cache_identity
.weight
= htons(Config
.Wccp2
.weight
);
764 memset(&wccp2_identity_info
.cache_identity
.status
, '\0', sizeof(wccp2_identity_info
.cache_identity
.status
));
766 xmemcpy(ptr
, &wccp2_identity_info
, sizeof(struct wccp2_identity_info_t
));
767 service_list_ptr
->wccp2_identity_info_ptr
= ptr
;
769 ptr
+= sizeof(struct wccp2_identity_info_t
);
772 case WCCP2_ASSIGNMENT_METHOD_MASK
:
774 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_mask_identity_info_t
);
775 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
776 wccp2_mask_identity_info
.cache_identity_type
= htons(WCCP2_WC_ID_INFO
);
777 wccp2_mask_identity_info
.cache_identity_length
= htons(sizeof(wccp2_mask_identity_info
.cache_identity
));
778 memset(&wccp2_mask_identity_info
.cache_identity
.addr
, '\0', sizeof(struct in_addr
));
779 wccp2_mask_identity_info
.cache_identity
.num1
= htonl(2);
780 wccp2_mask_identity_info
.cache_identity
.num2
= htonl(1);
781 service_flags
= ntohl(service_list_ptr
->service_info
->service_flags
);
783 if ((service_flags
& WCCP2_SERVICE_SRC_IP_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
)) {
784 wccp2_mask_identity_info
.cache_identity
.source_ip_mask
= htonl(0x00001741);
785 wccp2_mask_identity_info
.cache_identity
.dest_ip_mask
= 0;
786 wccp2_mask_identity_info
.cache_identity
.source_port_mask
= 0;
787 wccp2_mask_identity_info
.cache_identity
.dest_port_mask
= 0;
788 } 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
)) {
789 wccp2_mask_identity_info
.cache_identity
.source_ip_mask
= 0;
790 wccp2_mask_identity_info
.cache_identity
.dest_ip_mask
= htonl(0x00001741);
791 wccp2_mask_identity_info
.cache_identity
.source_port_mask
= 0;
792 wccp2_mask_identity_info
.cache_identity
.dest_port_mask
= 0;
793 } else if ((service_flags
& WCCP2_SERVICE_SRC_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
)) {
794 wccp2_mask_identity_info
.cache_identity
.source_ip_mask
= 0;
795 wccp2_mask_identity_info
.cache_identity
.dest_ip_mask
= 0;
796 wccp2_mask_identity_info
.cache_identity
.source_port_mask
= htons(0x1741);
797 wccp2_mask_identity_info
.cache_identity
.dest_port_mask
= 0;
798 } else if ((service_flags
& WCCP2_SERVICE_DST_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
)) {
799 wccp2_mask_identity_info
.cache_identity
.source_ip_mask
= 0;
800 wccp2_mask_identity_info
.cache_identity
.dest_ip_mask
= 0;
801 wccp2_mask_identity_info
.cache_identity
.source_port_mask
= 0;
802 wccp2_mask_identity_info
.cache_identity
.dest_port_mask
= htons(0x1741);
804 fatalf("Unknown service hash method\n");
807 wccp2_mask_identity_info
.cache_identity
.num3
= 0;
808 wccp2_mask_identity_info
.cache_identity
.num4
= 0;
810 xmemcpy(ptr
, &wccp2_mask_identity_info
, sizeof(struct wccp2_mask_identity_info_t
));
811 service_list_ptr
->wccp2_identity_info_ptr
= ptr
;
813 ptr
+= sizeof(struct wccp2_mask_identity_info_t
);
817 fatalf("Unknown Wccp2 assignment method\n");
820 /* Add the cache view section */
821 wccp2_here_i_am_header
.length
+= sizeof(wccp2_cache_view_header
);
823 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
825 wccp2_cache_view_header
.cache_view_type
= htons(WCCP2_WC_VIEW_INFO
);
827 wccp2_cache_view_header
.cache_view_length
= htons(sizeof(wccp2_cache_view_header
) - 4 +
828 sizeof(wccp2_cache_view_info
) + (wccp2_numrouters
* sizeof(wccp2_router_id_element
)));
830 wccp2_cache_view_header
.cache_view_version
= htonl(1);
832 xmemcpy(ptr
, &wccp2_cache_view_header
, sizeof(wccp2_cache_view_header
));
834 ptr
+= sizeof(wccp2_cache_view_header
);
836 /* Add the number of routers to the packet */
837 wccp2_here_i_am_header
.length
+= sizeof(service_list_ptr
->num_routers
);
839 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
841 service_list_ptr
->num_routers
= htonl(wccp2_numrouters
);
843 xmemcpy(ptr
, &service_list_ptr
->num_routers
, sizeof(service_list_ptr
->num_routers
));
845 ptr
+= sizeof(service_list_ptr
->num_routers
);
847 /* Add each router. Keep this functionality here to make sure the received_id can be updated in the packet */
848 for (s
= Config
.Wccp2
.router
; s
; s
= s
->next
) {
849 if (!s
->s
.IsAnyAddr()) {
851 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_router_id_element_t
);
852 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
854 /* Add a pointer to the router list for this router */
856 router_list_ptr
->info
= (struct wccp2_router_id_element_t
*) ptr
;
857 s
->s
.GetInAddr(router_list_ptr
->info
->router_address
);
858 router_list_ptr
->info
->received_id
= htonl(0);
859 s
->s
.GetInAddr(router_list_ptr
->router_sendto_address
);
860 router_list_ptr
->member_change
= htonl(0);
862 /* Build the next struct */
864 router_list_ptr
->next
= (wccp2_router_list_t
*) xcalloc(1, sizeof(struct wccp2_router_list_t
));
866 /* update the pointer */
867 router_list_ptr
= router_list_ptr
->next
;
868 router_list_ptr
->next
= NULL
;
870 /* no need to copy memory - we've just set the values directly in the packet above */
872 ptr
+= sizeof(struct wccp2_router_id_element_t
);
876 /* Add the number of caches (0) */
877 wccp2_here_i_am_header
.length
+= sizeof(wccp2_cache_view_info
.num_caches
);
879 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
881 wccp2_cache_view_info
.num_caches
= htonl(0);
883 xmemcpy(ptr
, &wccp2_cache_view_info
.num_caches
, sizeof(wccp2_cache_view_info
.num_caches
));
885 ptr
+= sizeof(wccp2_cache_view_info
.num_caches
);
887 /* Add the extra capability header */
888 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_info_header
);
890 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
892 wccp2_capability_info_header
.capability_info_type
= htons(WCCP2_CAPABILITY_INFO
);
894 wccp2_capability_info_header
.capability_info_length
= htons(3 * sizeof(wccp2_capability_element
));
896 xmemcpy(ptr
, &wccp2_capability_info_header
, sizeof(wccp2_capability_info_header
));
898 ptr
+= sizeof(wccp2_capability_info_header
);
900 /* Add the forwarding method */
901 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_element
);
903 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
905 wccp2_capability_element
.capability_type
= htons(WCCP2_CAPABILITY_FORWARDING_METHOD
);
907 wccp2_capability_element
.capability_length
= htons(sizeof(wccp2_capability_element
.capability_value
));
909 wccp2_capability_element
.capability_value
= htonl(Config
.Wccp2
.forwarding_method
);
911 xmemcpy(ptr
, &wccp2_capability_element
, sizeof(wccp2_capability_element
));
913 ptr
+= sizeof(wccp2_capability_element
);
915 /* Add the assignment method */
916 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_element
);
918 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
920 wccp2_capability_element
.capability_type
= htons(WCCP2_CAPABILITY_ASSIGNMENT_METHOD
);
922 wccp2_capability_element
.capability_length
= htons(sizeof(wccp2_capability_element
.capability_value
));
924 wccp2_capability_element
.capability_value
= htonl(Config
.Wccp2
.assignment_method
);
926 xmemcpy(ptr
, &wccp2_capability_element
, sizeof(wccp2_capability_element
));
928 ptr
+= sizeof(wccp2_capability_element
);
930 /* Add the return method */
931 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_element
);
933 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
935 wccp2_capability_element
.capability_type
= htons(WCCP2_CAPABILITY_RETURN_METHOD
);
937 wccp2_capability_element
.capability_length
= htons(sizeof(wccp2_capability_element
.capability_value
));
939 wccp2_capability_element
.capability_value
= htonl(Config
.Wccp2
.return_method
);
941 xmemcpy(ptr
, &wccp2_capability_element
, sizeof(wccp2_capability_element
));
943 ptr
+= sizeof(wccp2_capability_element
);
945 /* Finally, fix the total length to network order, and copy to the appropriate memory blob */
946 wccp2_here_i_am_header
.length
= htons(wccp2_here_i_am_header
.length
);
948 memcpy(&service_list_ptr
->wccp_packet
, &wccp2_here_i_am_header
, sizeof(wccp2_here_i_am_header
));
950 service_list_ptr
->wccp_packet_size
= ntohs(wccp2_here_i_am_header
.length
) + sizeof(wccp2_here_i_am_header
);
952 /* Add the event if everything initialised correctly */
953 if (wccp2_numrouters
) {
954 if (!eventFind(wccp2HereIam
, NULL
)) {
955 eventAdd("wccp2HereIam", wccp2HereIam
, NULL
, 1, 1);
959 service_list_ptr
= service_list_ptr
->next
;
964 wccp2ConnectionOpen(void)
966 struct sockaddr_in router
, local
, null
;
967 socklen_t local_len
, router_len
;
969 struct wccp2_service_list_t
*service_list_ptr
;
971 struct wccp2_router_list_t
*router_list_ptr
;
973 debugs(80, 5, "wccp2ConnectionOpen: Called");
975 if (wccp2_numrouters
== 0 || !wccp2_service_list_head
) {
976 debugs(80, 2, "WCCPv2 Disabled.");
980 if( !Config
.Wccp2
.address
.SetIPv4() ) {
981 debugs(80, 0, "WCCPv2 Disabled. " << Config
.Wccp2
.address
<< " is not an IPv4 address.");
985 Config
.Wccp2
.address
.SetPort(WCCP_PORT
);
986 theWccp2Connection
= comm_open(SOCK_DGRAM
,
988 Config
.Wccp2
.address
,
992 if (theWccp2Connection
< 0)
993 fatal("Cannot open WCCP Port");
995 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
997 int i
= IP_PMTUDISC_DONT
;
998 setsockopt(theWccp2Connection
, SOL_IP
, IP_MTU_DISCOVER
, &i
, sizeof i
);
1002 commSetSelect(theWccp2Connection
,
1008 debugs(80, 1, "Accepting WCCPv2 messages on port " << WCCP_PORT
<< ", FD " << theWccp2Connection
<< ".");
1009 debugs(80, 1, "Initialising all WCCPv2 lists");
1011 /* Initialise all routers on all services */
1012 memset(&null
, 0, sizeof(null
));
1014 null
.sin_family
= AF_UNSPEC
;
1016 service_list_ptr
= wccp2_service_list_head
;
1018 while (service_list_ptr
!= NULL
) {
1019 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1020 router_len
= sizeof(router
);
1021 memset(&router
, '\0', router_len
);
1022 router
.sin_family
= AF_INET
;
1023 router
.sin_port
= htons(WCCP_PORT
);
1024 router
.sin_addr
= router_list_ptr
->router_sendto_address
;
1026 if (connect(theWccp2Connection
, (struct sockaddr
*) &router
, router_len
))
1027 fatal("Unable to connect WCCP out socket");
1029 local_len
= sizeof(local
);
1031 memset(&local
, '\0', local_len
);
1033 if (getsockname(theWccp2Connection
, (struct sockaddr
*) &local
, &local_len
))
1034 fatal("Unable to getsockname on WCCP out socket");
1036 router_list_ptr
->local_ip
= local
.sin_addr
;
1038 /* Disconnect the sending socket. Note: FreeBSD returns error
1039 * but disconnects anyway so we have to just assume it worked
1041 if (wccp2_numrouters
> 1)
1042 connect(theWccp2Connection
, (struct sockaddr
*) &null
, router_len
);
1045 service_list_ptr
= service_list_ptr
->next
;
1048 wccp2_connected
= 1;
1052 wccp2ConnectionClose(void)
1055 struct wccp2_service_list_t
*service_list_ptr
;
1057 struct wccp2_service_list_t
*service_list_ptr_next
;
1059 struct wccp2_router_list_t
*router_list_ptr
;
1061 struct wccp2_router_list_t
*router_list_next
;
1063 struct wccp2_cache_list_t
*cache_list_ptr
;
1065 struct wccp2_cache_list_t
*cache_list_ptr_next
;
1067 if (wccp2_connected
== 0) {
1071 if (theWccp2Connection
> -1) {
1072 debugs(80, 1, "FD " << theWccp2Connection
<< " Closing WCCPv2 socket");
1073 comm_close(theWccp2Connection
);
1074 theWccp2Connection
= -1;
1077 /* for each router on each service send a packet */
1078 service_list_ptr
= wccp2_service_list_head
;
1080 while (service_list_ptr
!= NULL
) {
1081 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
!= NULL
; router_list_ptr
= router_list_next
) {
1082 for (cache_list_ptr
= &router_list_ptr
->cache_list_head
; cache_list_ptr
; cache_list_ptr
= cache_list_ptr_next
) {
1083 cache_list_ptr_next
= cache_list_ptr
->next
;
1085 if (cache_list_ptr
!= &router_list_ptr
->cache_list_head
) {
1086 xfree(cache_list_ptr
);
1089 memset(cache_list_ptr
, '\0', sizeof(struct wccp2_cache_list_t
));
1093 router_list_next
= router_list_ptr
->next
;
1095 if (router_list_ptr
!= &service_list_ptr
->router_list_head
) {
1096 xfree(router_list_ptr
);
1099 memset(router_list_ptr
, '\0', sizeof(struct wccp2_router_list_t
));
1103 service_list_ptr_next
= service_list_ptr
->next
;
1104 xfree(service_list_ptr
);
1105 service_list_ptr
= service_list_ptr_next
;
1108 wccp2_service_list_head
= NULL
;
1109 eventDelete(wccp2HereIam
, NULL
);
1110 eventDelete(wccp2AssignBuckets
, NULL
);
1111 eventDelete(wccp2HereIam
, NULL
);
1112 wccp2_connected
= 0;
1116 * Functions for handling the requests.
1120 * Accept the UDP packet
1123 wccp2HandleUdp(int sock
, void *not_used
)
1126 struct wccp2_service_list_t
*service_list_ptr
;
1128 struct wccp2_router_list_t
*router_list_ptr
;
1130 struct wccp2_cache_list_t
*cache_list_ptr
;
1132 struct wccp2_cache_list_t
*cache_list_ptr_next
;
1134 /* These structs form the parts of the packet */
1136 struct wccp2_item_header_t
*header
= NULL
;
1138 struct wccp2_security_none_t
*security_info
= NULL
;
1140 struct wccp2_service_info_t
*service_info
= NULL
;
1142 struct router_identity_info_t
*router_identity_info
= NULL
;
1144 struct router_view_t
*router_view_header
= NULL
;
1146 struct wccp2_cache_mask_identity_info_t
*cache_mask_identity
= NULL
;
1148 struct cache_mask_info_t
*cache_mask_info
= NULL
;
1150 struct wccp2_cache_identity_info_t
*cache_identity
= NULL
;
1152 struct wccp2_capability_info_header_t
*router_capability_header
= NULL
;
1154 struct wccp2_capability_element_t
*router_capability_element
;
1156 struct sockaddr_in from
;
1158 struct IN_ADDR cache_address
;
1160 short int data_length
, offset
;
1165 debugs(80, 6, "wccp2HandleUdp: Called.");
1167 commSetSelect(sock
, COMM_SELECT_READ
, wccp2HandleUdp
, NULL
, 0);
1169 /* FIXME INET6 : drop conversion boundary */ IPAddress from_tmp
;
1171 len
= comm_udp_recvfrom(sock
,
1176 /* FIXME INET6 : drop conversion boundary */ from_tmp
.GetSockAddr(from
);
1181 if (ntohs(wccp2_i_see_you
.version
) != WCCP2_VERSION
)
1184 if (ntohl(wccp2_i_see_you
.type
) != WCCP2_I_SEE_YOU
)
1187 debugs(80, 3, "Incoming WCCPv2 I_SEE_YOU length " << ntohs(wccp2_i_see_you
.length
) << ".");
1189 /* Record the total data length */
1190 data_length
= ntohs(wccp2_i_see_you
.length
);
1194 if (data_length
> len
) {
1195 debugs(80, 1, "ERROR: Malformed WCCPv2 packet claiming it's bigger than received data");
1199 /* Go through the data structure */
1200 while (data_length
> offset
) {
1202 header
= (struct wccp2_item_header_t
*) &wccp2_i_see_you
.data
[offset
];
1204 switch (ntohs(header
->type
)) {
1206 case WCCP2_SECURITY_INFO
:
1208 if (security_info
!= NULL
) {
1209 debugs(80, 1, "Duplicate security definition");
1213 security_info
= (struct wccp2_security_none_t
*) &wccp2_i_see_you
.data
[offset
];
1216 case WCCP2_SERVICE_INFO
:
1218 if (service_info
!= NULL
) {
1219 debugs(80, 1, "Duplicate service_info definition");
1223 service_info
= (struct wccp2_service_info_t
*) &wccp2_i_see_you
.data
[offset
];
1226 case WCCP2_ROUTER_ID_INFO
:
1228 if (router_identity_info
!= NULL
) {
1229 debugs(80, 1, "Duplicate router_identity_info definition");
1233 router_identity_info
= (struct router_identity_info_t
*) &wccp2_i_see_you
.data
[offset
];
1236 case WCCP2_RTR_VIEW_INFO
:
1238 if (router_view_header
!= NULL
) {
1239 debugs(80, 1, "Duplicate router_view definition");
1243 router_view_header
= (struct router_view_t
*) &wccp2_i_see_you
.data
[offset
];
1246 case WCCP2_CAPABILITY_INFO
:
1248 if (router_capability_header
!= NULL
) {
1249 debugs(80, 1, "Duplicate router_capability definition");
1253 router_capability_header
= (struct wccp2_capability_info_header_t
*) &wccp2_i_see_you
.data
[offset
];
1256 /* Nothing to do for the types below */
1258 case WCCP2_ASSIGN_MAP
:
1262 debugs(80, 1, "Unknown record type in WCCPv2 Packet (" << ntohs(header
->type
) << ").");
1265 offset
+= sizeof(struct wccp2_item_header_t
);
1266 offset
+= ntohs(header
->length
);
1268 if (offset
> data_length
) {
1269 debugs(80, 1, "Error: WCCPv2 packet tried to tell us there is data beyond the end of the packet");
1274 if ((security_info
== NULL
) || (service_info
== NULL
) || (router_identity_info
== NULL
) || (router_view_header
== NULL
)) {
1275 debugs(80, 1, "Incomplete WCCPv2 Packet");
1279 debugs(80, 5, "Complete packet received");
1281 /* Check that the service in the packet is configured on this router */
1282 service_list_ptr
= wccp2_service_list_head
;
1284 while (service_list_ptr
!= NULL
) {
1285 if (service_info
->service_id
== service_list_ptr
->service_info
->service_id
) {
1289 service_list_ptr
= service_list_ptr
->next
;
1292 if (service_list_ptr
== NULL
) {
1293 debugs(80, 1, "WCCPv2 Unknown service received from router (" << service_info
->service_id
<< ")");
1297 if (ntohl(security_info
->security_option
) != ntohl(service_list_ptr
->security_info
->security_option
)) {
1298 debugs(80, 1, "Invalid security option in WCCPv2 Packet (" << ntohl(security_info
->security_option
) << " vs " << ntohl(service_list_ptr
->security_info
->security_option
) << ").");
1302 if (!wccp2_check_security(service_list_ptr
, (char *) security_info
, (char *) &wccp2_i_see_you
, len
)) {
1303 debugs(80, 1, "Received WCCPv2 Packet failed authentication");
1307 /* Check that the router address is configured on this router */
1308 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1309 if (router_list_ptr
->router_sendto_address
.s_addr
== from
.sin_addr
.s_addr
)
1313 if (router_list_ptr
->next
== NULL
) {
1314 debugs(80, 1, "WCCPv2 Packet received from unknown router");
1318 /* Set the router id */
1319 router_list_ptr
->info
->router_address
= router_identity_info
->router_id_element
.router_address
;
1321 /* Increment the received id in the packet */
1322 if (ntohl(router_list_ptr
->info
->received_id
) != ntohl(router_identity_info
->router_id_element
.received_id
)) {
1323 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
) << ".");
1324 router_list_ptr
->info
->received_id
= router_identity_info
->router_id_element
.received_id
;
1327 /* TODO: check return/forwarding methods */
1328 if (router_capability_header
== NULL
) {
1329 if ((Config
.Wccp2
.return_method
!= WCCP2_PACKET_RETURN_METHOD_GRE
) || (Config
.Wccp2
.forwarding_method
!= WCCP2_FORWARDING_METHOD_GRE
)) {
1330 debugs(80, 1, "wccp2HandleUdp: fatal error - A WCCP router does not support the forwarding method specified, only GRE supported");
1331 wccp2ConnectionClose();
1336 char *end
= ((char *) router_capability_header
) + sizeof(*router_capability_header
) + ntohs(router_capability_header
->capability_info_length
) - sizeof(struct wccp2_capability_info_header_t
);
1338 router_capability_element
= (struct wccp2_capability_element_t
*) (((char *) router_capability_header
) + sizeof(*router_capability_header
));
1340 while ((char *) router_capability_element
<= end
) {
1342 switch (ntohs(router_capability_element
->capability_type
)) {
1344 case WCCP2_CAPABILITY_FORWARDING_METHOD
:
1346 if (!(ntohl(router_capability_element
->capability_value
) & Config
.Wccp2
.forwarding_method
)) {
1347 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
);
1348 wccp2ConnectionClose();
1354 case WCCP2_CAPABILITY_ASSIGNMENT_METHOD
:
1356 if (!(ntohl(router_capability_element
->capability_value
) & Config
.Wccp2
.assignment_method
)) {
1357 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
);
1358 wccp2ConnectionClose();
1364 case WCCP2_CAPABILITY_RETURN_METHOD
:
1366 if (!(ntohl(router_capability_element
->capability_value
) & Config
.Wccp2
.return_method
)) {
1367 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
);
1368 wccp2ConnectionClose();
1375 debugs(80, 1, "Unknown capability type in WCCPv2 Packet (" << ntohs(router_capability_element
->capability_type
) << ").");
1378 router_capability_element
= (struct wccp2_capability_element_t
*) (((char *) router_capability_element
) + sizeof(struct wccp2_capability_element_header_t
) + ntohs(router_capability_element
->capability_length
));
1382 debugs(80, 5, "Cleaning out cache list");
1383 /* clean out the old cache list */
1385 for (cache_list_ptr
= &router_list_ptr
->cache_list_head
; cache_list_ptr
; cache_list_ptr
= cache_list_ptr_next
) {
1386 cache_list_ptr_next
= cache_list_ptr
->next
;
1388 if (cache_list_ptr
!= &router_list_ptr
->cache_list_head
) {
1389 xfree(cache_list_ptr
);
1393 router_list_ptr
->num_caches
= htonl(0);
1396 /* Check to see if we're the master cache and update the cache list */
1398 service_list_ptr
->lowest_ip
= 1;
1399 cache_list_ptr
= &router_list_ptr
->cache_list_head
;
1401 /* to find the list of caches, we start at the end of the router view header */
1403 ptr
= (char *) (router_view_header
) + sizeof(struct router_view_t
);
1405 /* Then we read the number of routers */
1406 memcpy(&tmp
, ptr
, sizeof(tmp
));
1408 /* skip the number plus all the ip's */
1410 ptr
+= sizeof(tmp
) + (ntohl(tmp
) * sizeof(struct IN_ADDR
));
1412 /* Then read the number of caches */
1413 memcpy(&tmp
, ptr
, sizeof(tmp
));
1416 if (ntohl(tmp
) != 0) {
1417 /* search through the list of received-from ip addresses */
1419 for (num_caches
= 0; num_caches
< (int) ntohl(tmp
); num_caches
++) {
1420 /* Get a copy of the ip */
1422 switch (Config
.Wccp2
.assignment_method
) {
1424 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1426 cache_identity
= (struct wccp2_cache_identity_info_t
*) ptr
;
1428 ptr
+= sizeof(struct wccp2_cache_identity_info_t
);
1430 memcpy(&cache_address
, &cache_identity
->addr
, sizeof(struct IN_ADDR
));
1432 cache_list_ptr
->weight
= ntohs(cache_identity
->weight
);
1435 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1437 cache_mask_info
= (struct cache_mask_info_t
*) ptr
;
1439 /* The mask assignment has an undocumented variable length entry here */
1441 if (ntohl(cache_mask_info
->num1
) == 3) {
1443 cache_mask_identity
= (struct wccp2_cache_mask_identity_info_t
*) ptr
;
1445 ptr
+= sizeof(struct wccp2_cache_mask_identity_info_t
);
1447 memcpy(&cache_address
, &cache_mask_identity
->addr
, sizeof(struct IN_ADDR
));
1450 ptr
+= sizeof(struct cache_mask_info_t
);
1452 memcpy(&cache_address
, &cache_mask_info
->addr
, sizeof(struct IN_ADDR
));
1455 cache_list_ptr
->weight
= 0;
1459 fatalf("Unknown Wccp2 assignment method\n");
1462 /* Update the cache list */
1463 cache_list_ptr
->cache_ip
= cache_address
;
1465 cache_list_ptr
->next
= (wccp2_cache_list_t
*) xcalloc(1, sizeof(struct wccp2_cache_list_t
));
1467 cache_list_ptr
= cache_list_ptr
->next
;
1469 cache_list_ptr
->next
= NULL
;
1471 debugs (80, 5, "checking cache list: (" << std::hex
<< cache_address
.s_addr
<< ":" << router_list_ptr
->local_ip
.s_addr
<< ")");
1473 /* Check to see if it's the master, or us */
1475 if (cache_address
.s_addr
== router_list_ptr
->local_ip
.s_addr
) {
1479 if (cache_address
.s_addr
< router_list_ptr
->local_ip
.s_addr
) {
1480 service_list_ptr
->lowest_ip
= 0;
1484 debugs(80, 5, "Adding ourselves as the only cache");
1486 /* Update the cache list */
1487 cache_list_ptr
->cache_ip
= router_list_ptr
->local_ip
;
1489 cache_list_ptr
->next
= (wccp2_cache_list_t
*) xcalloc(1, sizeof(struct wccp2_cache_list_t
));
1490 cache_list_ptr
= cache_list_ptr
->next
;
1491 cache_list_ptr
->next
= NULL
;
1493 service_list_ptr
->lowest_ip
= 1;
1498 router_list_ptr
->num_caches
= htonl(num_caches
);
1500 if ((found
== 1) && (service_list_ptr
->lowest_ip
== 1)) {
1501 if (ntohl(router_view_header
->change_number
) != router_list_ptr
->member_change
) {
1502 debugs(80, 4, "Change detected - queueing up new assignment");
1503 router_list_ptr
->member_change
= ntohl(router_view_header
->change_number
);
1504 eventDelete(wccp2AssignBuckets
, NULL
);
1505 eventAdd("wccp2AssignBuckets", wccp2AssignBuckets
, NULL
, 15.0, 1);
1507 debugs(80, 5, "Change not detected (" << ntohl(router_view_header
->change_number
) << " = " << router_list_ptr
->member_change
<< ")");
1510 eventDelete(wccp2AssignBuckets
, NULL
);
1511 debugs(80, 5, "I am not the lowest ip cache - not assigning buckets");
1516 wccp2HereIam(void *voidnotused
)
1519 struct wccp2_service_list_t
*service_list_ptr
;
1521 struct wccp2_router_list_t
*router_list_ptr
;
1523 struct wccp2_identity_info_t
*wccp2_identity_info_ptr
;
1525 struct wccp2_mask_identity_info_t
*wccp2_mask_identity_info_ptr
;
1529 debugs(80, 6, "wccp2HereIam: Called");
1531 if (wccp2_connected
== 0) {
1532 debugs(80, 1, "wccp2HereIam: wccp2 socket closed. Shutting down WCCP2");
1536 /* Wait if store dirs are rebuilding */
1537 if (StoreController::store_dirs_rebuilding
&& Config
.Wccp2
.rebuildwait
) {
1538 eventAdd("wccp2HereIam", wccp2HereIam
, NULL
, 1.0, 1);
1542 router
.SetPort(WCCP_PORT
);
1544 /* for each router on each service send a packet */
1545 service_list_ptr
= wccp2_service_list_head
;
1547 while (service_list_ptr
!= NULL
) {
1548 debugs(80, 5, "wccp2HereIam: sending to service id " << service_list_ptr
->info
.service_id
);
1550 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1551 router
= router_list_ptr
->router_sendto_address
;
1553 /* Set the cache id (ip) */
1555 switch (Config
.Wccp2
.assignment_method
) {
1557 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1559 wccp2_identity_info_ptr
= (struct wccp2_identity_info_t
*) service_list_ptr
->wccp2_identity_info_ptr
;
1560 wccp2_identity_info_ptr
->cache_identity
.addr
= router_list_ptr
->local_ip
;
1563 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1565 wccp2_mask_identity_info_ptr
= (struct wccp2_mask_identity_info_t
*) service_list_ptr
->wccp2_identity_info_ptr
;
1566 wccp2_mask_identity_info_ptr
->cache_identity
.addr
= router_list_ptr
->local_ip
;
1570 fatalf("Unknown Wccp2 assignment method\n");
1573 /* Security update, if needed */
1575 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
1576 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
);
1579 debugs(80, 3, "Sending HereIam packet size " << service_list_ptr
->wccp_packet_size
);
1580 /* Send the packet */
1582 if (wccp2_numrouters
> 1) {
1583 comm_udp_sendto(theWccp2Connection
,
1585 &service_list_ptr
->wccp_packet
,
1586 service_list_ptr
->wccp_packet_size
);
1588 send(theWccp2Connection
,
1589 &service_list_ptr
->wccp_packet
,
1590 service_list_ptr
->wccp_packet_size
,
1595 service_list_ptr
= service_list_ptr
->next
;
1598 eventAdd("wccp2HereIam", wccp2HereIam
, NULL
, 10.0, 1);
1602 wccp2AssignBuckets(void *voidnotused
)
1605 struct wccp2_service_list_t
*service_list_ptr
;
1607 struct wccp2_router_list_t
*router_list_ptr
;
1609 struct wccp2_cache_list_t
*cache_list_ptr
;
1610 char wccp_packet
[WCCP_RESPONSE_SIZE
];
1611 short int offset
, saved_offset
, assignment_offset
, alt_assignment_offset
;
1613 struct sockaddr_in router
;
1616 uint32_t service_flags
;
1617 u_short port
= WCCP_PORT
;
1619 /* Packet segments */
1621 struct wccp2_here_i_am_header_t
*main_header
;
1623 struct wccp2_security_md5_t
*security
= NULL
;
1624 /* service from service struct */
1626 struct wccp2_item_header_t
*assignment_header
;
1628 struct wccp2_item_header_t
*alt_assignment_type_header
= NULL
;
1630 struct assignment_key_t
*assignment_key
;
1631 /* number of routers */
1633 struct wccp2_router_assign_element_t
*router_assign
;
1634 /* number of caches */
1636 struct IN_ADDR
*cache_address
;
1637 /* Alternative assignement mask/values */
1640 struct wccp2_mask_element_t
*mask_element
;
1642 struct wccp2_value_element_t
*value_element
;
1643 int valuecounter
, value
;
1646 assignment_offset
= alt_assignment_offset
= 0;
1648 router_len
= sizeof(router
);
1649 memset(&router
, '\0', router_len
);
1650 router
.sin_family
= AF_INET
;
1651 router
.sin_port
= htons(port
);
1653 /* Start main header - fill in length later */
1656 main_header
= (struct wccp2_here_i_am_header_t
*) &wccp_packet
[offset
];
1657 main_header
->type
= htonl(WCCP2_REDIRECT_ASSIGN
);
1658 main_header
->version
= htons(WCCP2_VERSION
);
1660 debugs(80, 2, "Running wccp2AssignBuckets");
1661 service_list_ptr
= wccp2_service_list_head
;
1663 while (service_list_ptr
!= NULL
) {
1664 /* If we're not the lowest, we don't need to worry */
1666 if (service_list_ptr
->lowest_ip
== 0) {
1668 service_list_ptr
= service_list_ptr
->next
;
1672 /* reset the offset */
1674 offset
= sizeof(struct wccp2_here_i_am_header_t
);
1676 /* build packet header from hereIam packet */
1678 /* XXX this should be made more generic! */
1679 /* XXX and I hate magic numbers! */
1680 switch (service_list_ptr
->wccp2_security_type
) {
1682 case WCCP2_NO_SECURITY
:
1684 security
= (struct wccp2_security_md5_t
*) &wccp_packet
[offset
];
1685 memcpy(security
, service_list_ptr
->security_info
, 8);
1689 case WCCP2_MD5_SECURITY
:
1691 security
= (struct wccp2_security_md5_t
*) &wccp_packet
[offset
];
1693 memcpy(security
, service_list_ptr
->security_info
, sizeof(struct wccp2_security_md5_t
));
1695 offset
+= sizeof(struct wccp2_security_md5_t
);
1699 fatalf("Unknown Wccp2 security type\n");
1704 memcpy(&wccp_packet
[offset
], service_list_ptr
->service_info
, sizeof(struct wccp2_service_info_t
));
1706 offset
+= sizeof(struct wccp2_service_info_t
);
1708 /* assignment header - fill in length later */
1710 assignment_header
= (struct wccp2_item_header_t
*) &wccp_packet
[offset
];
1712 switch (Config
.Wccp2
.assignment_method
) {
1714 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1715 assignment_header
->type
= htons(WCCP2_REDIRECT_ASSIGNMENT
);
1717 offset
+= sizeof(struct wccp2_item_header_t
);
1718 assignment_offset
= offset
;
1721 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1722 assignment_header
->type
= htons(WCCP2_ALT_ASSIGNMENT
);
1724 offset
+= sizeof(struct wccp2_item_header_t
);
1725 assignment_offset
= offset
;
1727 /* The alternative assignment has an extra header, fill in length later */
1729 alt_assignment_type_header
= (struct wccp2_item_header_t
*) &wccp_packet
[offset
];
1730 alt_assignment_type_header
->type
= htons(WCCP2_MASK_ASSIGNMENT
);
1732 offset
+= sizeof(struct wccp2_item_header_t
);
1733 alt_assignment_offset
= offset
;
1738 fatalf("Unknown Wccp2 assignment method\n");
1741 /* Assignment key - fill in master ip later */
1743 assignment_key
= (struct assignment_key_t
*) &wccp_packet
[offset
];
1745 assignment_key
->master_number
= htonl(++service_list_ptr
->change_num
);
1747 offset
+= sizeof(struct assignment_key_t
);
1749 /* Number of routers */
1750 xmemcpy(&wccp_packet
[offset
], &service_list_ptr
->num_routers
, sizeof(service_list_ptr
->num_routers
));
1752 offset
+= sizeof(service_list_ptr
->num_routers
);
1754 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1758 router_assign
= (struct wccp2_router_assign_element_t
*) &wccp_packet
[offset
];
1759 router_assign
->router_address
= router_list_ptr
->info
->router_address
;
1760 router_assign
->received_id
= router_list_ptr
->info
->received_id
;
1761 router_assign
->change_number
= htonl(router_list_ptr
->member_change
);
1763 offset
+= sizeof(struct wccp2_router_assign_element_t
);
1766 saved_offset
= offset
;
1768 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1769 unsigned long *weight
= (unsigned long *)xcalloc(sizeof(*weight
), ntohl(router_list_ptr
->num_caches
));
1770 unsigned long total_weight
= 0;
1771 int num_caches
= ntohl(router_list_ptr
->num_caches
);
1773 offset
= saved_offset
;
1775 switch (Config
.Wccp2
.assignment_method
) {
1777 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1778 /* Number of caches */
1779 xmemcpy(&wccp_packet
[offset
], &router_list_ptr
->num_caches
, sizeof(router_list_ptr
->num_caches
));
1780 offset
+= sizeof(router_list_ptr
->num_caches
);
1785 for (cache
= 0, cache_list_ptr
= &router_list_ptr
->cache_list_head
; cache_list_ptr
->next
; cache_list_ptr
= cache_list_ptr
->next
, cache
++) {
1788 cache_address
= (struct IN_ADDR
*) &wccp_packet
[offset
];
1790 xmemcpy(cache_address
, &cache_list_ptr
->cache_ip
, sizeof(struct IN_ADDR
));
1791 total_weight
+= cache_list_ptr
->weight
<< 12;
1792 weight
[cache
] = cache_list_ptr
->weight
<< 12;
1794 offset
+= sizeof(struct IN_ADDR
);
1799 buckets
= (char *) &wccp_packet
[offset
];
1801 memset(buckets
, '\0', WCCP_BUCKETS
);
1803 if (num_caches
!= 0) {
1804 if (total_weight
== 0) {
1805 for (bucket_counter
= 0; bucket_counter
< WCCP_BUCKETS
; bucket_counter
++) {
1806 buckets
[bucket_counter
] = (char) (bucket_counter
% num_caches
);
1809 unsigned long *assigned
= (unsigned long *)xcalloc(sizeof(*assigned
), num_caches
);
1810 unsigned long done
= 0;
1812 unsigned long per_bucket
= total_weight
/ WCCP_BUCKETS
;
1814 for (bucket_counter
= 0; bucket_counter
< WCCP_BUCKETS
; bucket_counter
++) {
1818 for (n
= num_caches
; n
; n
--) {
1821 if (cache
>= num_caches
)
1824 if (!weight
[cache
]) {
1829 if (assigned
[cache
] <= done
)
1833 buckets
[bucket_counter
] = (char) cache
;
1834 step
= per_bucket
* total_weight
/ weight
[cache
];
1835 assigned
[cache
] += step
;
1839 safe_free(assigned
);
1843 offset
+= (WCCP_BUCKETS
* sizeof(char));
1847 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1848 num_maskval
= htonl(1);
1849 xmemcpy(&wccp_packet
[offset
], &num_maskval
, sizeof(int));
1850 offset
+= sizeof(int);
1852 mask_element
= (struct wccp2_mask_element_t
*) &wccp_packet
[offset
];
1853 service_flags
= ntohl(service_list_ptr
->service_info
->service_flags
);
1855 if ((service_flags
& WCCP2_SERVICE_SRC_IP_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
)) {
1856 mask_element
->source_ip_mask
= htonl(0x00001741);
1857 mask_element
->dest_ip_mask
= 0;
1858 mask_element
->source_port_mask
= 0;
1859 mask_element
->dest_port_mask
= 0;
1860 } 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
)) {
1861 mask_element
->source_ip_mask
= 0;
1862 mask_element
->dest_ip_mask
= htonl(0x00001741);
1863 mask_element
->source_port_mask
= 0;
1864 mask_element
->dest_port_mask
= 0;
1865 } else if ((service_flags
& WCCP2_SERVICE_SRC_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
)) {
1866 mask_element
->source_ip_mask
= 0;
1867 mask_element
->dest_ip_mask
= 0;
1868 mask_element
->source_port_mask
= htons(0x1741);
1869 mask_element
->dest_port_mask
= 0;
1870 } else if ((service_flags
& WCCP2_SERVICE_DST_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
)) {
1871 mask_element
->source_ip_mask
= 0;
1872 mask_element
->dest_ip_mask
= 0;
1873 mask_element
->source_port_mask
= 0;
1874 mask_element
->dest_port_mask
= htons(0x1741);
1876 fatalf("Unknown service hash method\n");
1879 mask_element
->number_values
= htonl(64);
1881 offset
+= sizeof(struct wccp2_mask_element_t
);
1883 cache_list_ptr
= &router_list_ptr
->cache_list_head
;
1886 for (valuecounter
= 0; valuecounter
< 64; valuecounter
++) {
1888 value_element
= (struct wccp2_value_element_t
*) &wccp_packet
[offset
];
1890 /* Update the value according the the "correct" formula */
1892 for (value
++; (value
& 0x1741) != value
; value
++) {
1893 assert(value
<= 0x1741);
1896 if ((service_flags
& WCCP2_SERVICE_SRC_IP_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
)) {
1897 value_element
->source_ip_value
= htonl(value
);
1898 value_element
->dest_ip_value
= 0;
1899 value_element
->source_port_value
= 0;
1900 value_element
->dest_port_value
= 0;
1901 } 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
)) {
1902 value_element
->source_ip_value
= 0;
1903 value_element
->dest_ip_value
= htonl(value
);
1904 value_element
->source_port_value
= 0;
1905 value_element
->dest_port_value
= 0;
1906 } else if ((service_flags
& WCCP2_SERVICE_SRC_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
)) {
1907 value_element
->source_ip_value
= 0;
1908 value_element
->dest_ip_value
= 0;
1909 value_element
->source_port_value
= htons(value
);
1910 value_element
->dest_port_value
= 0;
1911 } else if ((service_flags
& WCCP2_SERVICE_DST_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
)) {
1912 value_element
->source_ip_value
= 0;
1913 value_element
->dest_ip_value
= 0;
1914 value_element
->source_port_value
= 0;
1915 value_element
->dest_port_value
= htons(value
);
1917 fatalf("Unknown service hash method\n");
1920 value_element
->cache_ip
= cache_list_ptr
->cache_ip
;
1922 offset
+= sizeof(struct wccp2_value_element_t
);
1925 /* Assign the next value to the next cache */
1927 if ((cache_list_ptr
->next
) && (cache_list_ptr
->next
->next
))
1928 cache_list_ptr
= cache_list_ptr
->next
;
1930 cache_list_ptr
= &router_list_ptr
->cache_list_head
;
1933 /* Fill in length */
1934 alt_assignment_type_header
->length
= htons(offset
- alt_assignment_offset
);
1939 fatalf("Unknown Wccp2 assignment method\n");
1942 /* Fill in length */
1944 assignment_header
->length
= htons(offset
- assignment_offset
);
1946 /* Fill in assignment key */
1947 assignment_key
->master_ip
= router_list_ptr
->local_ip
;
1951 main_header
->length
= htons(offset
- sizeof(struct wccp2_here_i_am_header_t
));
1953 /* set the destination address */
1954 router
.sin_addr
= router_list_ptr
->router_sendto_address
;
1956 /* Security update, if needed */
1958 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
1959 wccp2_update_md5_security(service_list_ptr
->wccp_password
, (char *) security
, wccp_packet
, offset
);
1962 if (ntohl(router_list_ptr
->num_caches
)) {
1965 if (wccp2_numrouters
> 1) {
1966 /* FIXME INET6 : drop temp conversion */ IPAddress
tmp_rtr(router
);
1967 comm_udp_sendto(theWccp2Connection
,
1972 send(theWccp2Connection
,
1980 service_list_ptr
= service_list_ptr
->next
;
1986 * Configuration option parsing code
1992 * wccp2_service {standard|dynamic} {id} (password=password)
1995 parse_wccp2_service(void *v
)
2000 int security_type
= WCCP2_NO_SECURITY
;
2001 char wccp_password
[WCCP2_PASSWORD_LEN
+ 1];
2003 if (wccp2_connected
== 1) {
2004 debugs(80, 1, "WCCPv2: Somehow reparsing the configuration without having shut down WCCP! Try reloading squid again.");
2008 /* Snarf the type */
2009 if ((t
= strtok(NULL
, w_space
)) == NULL
) {
2010 debugs(80, 0, "wccp2ParseServiceInfo: missing service info type (standard|dynamic)");
2014 if (strcmp(t
, "standard") == 0) {
2015 service
= WCCP2_SERVICE_STANDARD
;
2016 } else if (strcmp(t
, "dynamic") == 0) {
2017 service
= WCCP2_SERVICE_DYNAMIC
;
2019 debugs(80, 0, "wccp2ParseServiceInfo: bad service info type (expected standard|dynamic, got " << t
<< ")");
2024 service_id
= GetInteger();
2026 if (service_id
< 0 || service_id
> 255) {
2027 debugs(80, 0, "wccp2ParseServiceInfo: service info id " << service_id
<< " is out of range (0..255)");
2031 memset(wccp_password
, 0, sizeof(wccp_password
));
2032 /* Handle password, if any */
2034 if ((t
= strtok(NULL
, w_space
)) != NULL
) {
2035 if (strncmp(t
, "password=", 9) == 0) {
2036 security_type
= WCCP2_MD5_SECURITY
;
2037 strncpy(wccp_password
, t
+ 9, WCCP2_PASSWORD_LEN
);
2041 /* Create a placeholder service record */
2042 wccp2_add_service_list(service
, service_id
, 0, 0, 0, empty_portlist
, security_type
, wccp_password
);
2046 dump_wccp2_service(StoreEntry
* e
, const char *label
, void *v
)
2049 struct wccp2_service_list_t
*srv
;
2050 srv
= wccp2_service_list_head
;
2052 while (srv
!= NULL
) {
2053 debugs(80, 3, "dump_wccp2_service: id " << srv
->info
.service_id
<< ", type " << srv
->info
.service
);
2054 storeAppendPrintf(e
, "%s %s %d", label
,
2055 (srv
->info
.service
== WCCP2_SERVICE_DYNAMIC
) ? "dynamic" : "standard",
2056 srv
->info
.service_id
);
2058 if (srv
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
2059 storeAppendPrintf(e
, " %s", srv
->wccp_password
);
2062 storeAppendPrintf(e
, "\n");
2069 free_wccp2_service(void *v
)
2073 check_null_wccp2_service(void *v
)
2075 return !wccp2_service_list_head
;
2081 * wccp2_service_info {id} stuff..
2085 * + flags=flag,flag,flag..
2086 * + proto=protocol (tcp|udp)
2087 * + ports=port,port,port (up to a max of 8)
2088 * + priority=priority (0->255)
2090 * The flags here are:
2091 * src_ip_hash, dst_ip_hash, source_port_hash, dst_port_hash, ports_defined,
2092 * ports_source, src_ip_alt_hash, dst_ip_alt_hash, src_port_alt_hash, dst_port_alt_hash
2095 parse_wccp2_service_flags(char *flags
)
2105 tmp
= xstrdup(flags
);
2108 flag
= strsep(&tmp2
, ",");
2111 if (strcmp(flag
, "src_ip_hash") == 0) {
2112 retflag
|= WCCP2_SERVICE_SRC_IP_HASH
;
2113 } else if (strcmp(flag
, "dst_ip_hash") == 0) {
2114 retflag
|= WCCP2_SERVICE_DST_IP_HASH
;
2115 } else if (strcmp(flag
, "source_port_hash") == 0) {
2116 retflag
|= WCCP2_SERVICE_SRC_PORT_HASH
;
2117 } else if (strcmp(flag
, "dst_port_hash") == 0) {
2118 retflag
|= WCCP2_SERVICE_DST_PORT_HASH
;
2119 } else if (strcmp(flag
, "ports_source") == 0) {
2120 retflag
|= WCCP2_SERVICE_PORTS_SOURCE
;
2121 } else if (strcmp(flag
, "src_ip_alt_hash") == 0) {
2122 retflag
|= WCCP2_SERVICE_SRC_IP_ALT_HASH
;
2123 } else if (strcmp(flag
, "dst_ip_alt_hash") == 0) {
2124 retflag
|= WCCP2_SERVICE_DST_IP_ALT_HASH
;
2125 } else if (strcmp(flag
, "src_port_alt_hash") == 0) {
2126 retflag
|= WCCP2_SERVICE_SRC_PORT_ALT_HASH
;
2127 } else if (strcmp(flag
, "dst_port_alt_hash") == 0) {
2128 retflag
|= WCCP2_SERVICE_DST_PORT_ALT_HASH
;
2130 fatalf("Unknown wccp2 service flag: %s\n", flag
);
2133 flag
= strsep(&tmp2
, ",");
2141 parse_wccp2_service_ports(char *options
, int portlist
[])
2145 char *tmp
, *tmp2
, *port
, *end
;
2151 tmp
= xstrdup(options
);
2154 port
= strsep(&tmp2
, ",");
2156 while (port
&& i
< WCCP2_NUMPORTS
) {
2157 p
= strtol(port
, &end
, 0);
2159 if (p
< 1 || p
> 65535) {
2160 fatalf("parse_wccp2_service_ports: port value '%s' isn't valid (1..65535)\n", port
);
2165 port
= strsep(&tmp2
, ",");
2169 fatalf("parse_wccp2_service_ports: too many ports (maximum: 8) in list '%s'\n", options
);
2176 parse_wccp2_service_info(void *v
)
2181 int portlist
[WCCP2_NUMPORTS
];
2182 int protocol
= -1; /* IPPROTO_TCP | IPPROTO_UDP */
2184 struct wccp2_service_list_t
*srv
;
2187 if (wccp2_connected
== 1) {
2188 debugs(80, 1, "WCCPv2: Somehow reparsing the configuration without having shut down WCCP! Try reloading squid again.");
2192 debugs(80, 5, "parse_wccp2_service_info: called");
2193 memset(portlist
, 0, sizeof(portlist
));
2194 /* First argument: id */
2195 service_id
= GetInteger();
2197 if (service_id
< 0 || service_id
> 255) {
2198 debugs(80, 1, "parse_wccp2_service_info: invalid service id " << service_id
<< " (must be between 0 .. 255)");
2202 /* Next: find the (hopefully!) existing service */
2203 srv
= wccp2_get_service_by_id(WCCP2_SERVICE_DYNAMIC
, service_id
);
2206 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
);
2209 /* Next: loop until we don't have any more tokens */
2210 while ((t
= strtok(NULL
, w_space
)) != NULL
) {
2211 if (strncmp(t
, "flags=", 6) == 0) {
2212 /* XXX eww, string pointer math */
2213 flags
= parse_wccp2_service_flags(t
+ 6);
2214 } else if (strncmp(t
, "ports=", 6) == 0) {
2215 parse_wccp2_service_ports(t
+ 6, portlist
);
2216 flags
|= WCCP2_SERVICE_PORTS_DEFINED
;
2217 } else if (strncmp(t
, "protocol=tcp", 12) == 0) {
2218 protocol
= IPPROTO_TCP
;
2219 } else if (strncmp(t
, "protocol=udp", 12) == 0) {
2220 protocol
= IPPROTO_UDP
;
2221 } else if (strncmp(t
, "protocol=", 9) == 0) {
2222 fatalf("parse_wccp2_service_info: id %d: unknown protocol (%s) - must be tcp or udp!\n", service_id
, t
);
2223 } else if (strncmp(t
, "priority=", 9) == 0) {
2224 priority
= strtol(t
+ 9, &end
, 0);
2226 if (priority
< 0 || priority
> 255) {
2227 fatalf("parse_wccp2_service_info: id %d: %s out of range (0..255)!\n", service_id
, t
);
2230 fatalf("parse_wccp2_service_info: id %d: unknown option '%s'\n", service_id
, t
);
2234 /* Check everything is set */
2235 if (priority
== -1) {
2236 fatalf("parse_wccp2_service_info: service %d: no priority defined (valid: 0..255)!\n", service_id
);
2239 if (protocol
== -1) {
2240 fatalf("parse_wccp2_service_info: service %d: no protocol defined (valid: tcp or udp)!\n", service_id
);
2243 if (!(flags
& WCCP2_SERVICE_PORTS_DEFINED
)) {
2244 fatalf("parse_wccp2_service_info: service %d: no ports defined!\n", service_id
);
2247 /* rightio! now we can update */
2248 wccp2_update_service(srv
, WCCP2_SERVICE_DYNAMIC
, service_id
, priority
,
2249 protocol
, flags
, portlist
);
2255 dump_wccp2_service_info(StoreEntry
* e
, const char *label
, void *v
)
2259 struct wccp2_service_list_t
*srv
;
2261 srv
= wccp2_service_list_head
;
2263 while (srv
!= NULL
) {
2264 debugs(80, 3, "dump_wccp2_service_info: id " << srv
->info
.service_id
<< " (type " << srv
->info
.service
<< ")");
2266 /* We don't need to spit out information for standard services */
2268 if (srv
->info
.service
== WCCP2_SERVICE_STANDARD
) {
2269 debugs(80, 3, "dump_wccp2_service_info: id " << srv
->info
.service_id
<< ": standard service, not dumping info");
2276 storeAppendPrintf(e
, "%s %d", label
, srv
->info
.service_id
);
2279 storeAppendPrintf(e
, " priority=%d", srv
->info
.service_priority
);
2282 flags
= ntohl(srv
->info
.service_flags
);
2286 storeAppendPrintf(e
, " flags=");
2288 if (flags
& WCCP2_SERVICE_SRC_IP_HASH
) {
2289 storeAppendPrintf(e
, "%ssrc_ip_hash", comma
? "," : "");
2293 if (flags
& WCCP2_SERVICE_DST_IP_HASH
) {
2294 storeAppendPrintf(e
, "%sdst_ip_hash", comma
? "," : "");
2298 if (flags
& WCCP2_SERVICE_SRC_PORT_HASH
) {
2299 storeAppendPrintf(e
, "%ssource_port_hash", comma
? "," : "");
2303 if (flags
& WCCP2_SERVICE_DST_PORT_HASH
) {
2304 storeAppendPrintf(e
, "%sdst_port_hash", comma
? "," : "");
2308 if (flags
& WCCP2_SERVICE_PORTS_DEFINED
) {
2309 storeAppendPrintf(e
, "%sports_defined", comma
? "," : "");
2313 if (flags
& WCCP2_SERVICE_PORTS_SOURCE
) {
2314 storeAppendPrintf(e
, "%sports_source", comma
? "," : "");
2318 if (flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
) {
2319 storeAppendPrintf(e
, "%ssrc_ip_alt_hash", comma
? "," : "");
2323 if (flags
& WCCP2_SERVICE_DST_IP_ALT_HASH
) {
2324 storeAppendPrintf(e
, "%ssrc_ip_alt_hash", comma
? "," : "");
2328 if (flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
) {
2329 storeAppendPrintf(e
, "%ssrc_port_alt_hash", comma
? "," : "");
2333 if (flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
) {
2334 storeAppendPrintf(e
, "%sdst_port_alt_hash", comma
? "," : "");
2342 if (srv
->info
.port0
!= 0) {
2343 storeAppendPrintf(e
, "%s%d", comma
? "," : " ports=", ntohs(srv
->info
.port0
));
2347 if (srv
->info
.port1
!= 0) {
2348 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port1
));
2352 if (srv
->info
.port2
!= 0) {
2353 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port2
));
2357 if (srv
->info
.port3
!= 0) {
2358 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port3
));
2362 if (srv
->info
.port4
!= 0) {
2363 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port4
));
2367 if (srv
->info
.port5
!= 0) {
2368 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port5
));
2372 if (srv
->info
.port6
!= 0) {
2373 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port6
));
2377 if (srv
->info
.port7
!= 0) {
2378 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port7
));
2383 storeAppendPrintf(e
, " protocol=%s", (srv
->info
.service_protocol
== IPPROTO_TCP
) ? "tcp" : "udp");
2385 storeAppendPrintf(e
, "\n");
2392 free_wccp2_service_info(void *v
)
2395 #endif /* USE_WCCPv2 */