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.
39 #include "comm/Connection.h"
40 #include "comm/Loops.h"
41 #include "ConfigParser.h"
43 #include "ip/Address.h"
53 #define WCCP_PORT 2048
54 #define WCCP_RESPONSE_SIZE 12448
55 #define WCCP_BUCKETS 256
57 static int theWccp2Connection
= -1;
58 static int wccp2_connected
= 0;
60 static PF wccp2HandleUdp
;
61 static EVH wccp2HereIam
;
62 static EVH wccp2AssignBuckets
;
66 #define WCCP2_HASH_ASSIGNMENT 0x00
67 #define WCCP2_MASK_ASSIGNMENT 0x01
69 #define WCCP2_NONE_SECURITY_LEN 0
70 #define WCCP2_MD5_SECURITY_LEN SQUID_MD5_DIGEST_LENGTH // 16
73 #define WCCP2_NUMPORTS 8
74 #define WCCP2_PASSWORD_LEN 8
76 /* WCCPv2 Pakcet format structures */
77 /* Defined in draft-wilson-wccp-v2-12-oct-2001.txt */
79 /** \interface WCCPv2_Protocol
80 * Generic header struct
82 struct wccp2_item_header_t
{
87 /* item type values */
88 #define WCCP2_SECURITY_INFO 0
89 #define WCCP2_SERVICE_INFO 1
90 #define WCCP2_ROUTER_ID_INFO 2
91 #define WCCP2_WC_ID_INFO 3
92 #define WCCP2_RTR_VIEW_INFO 4
93 #define WCCP2_WC_VIEW_INFO 5
94 #define WCCP2_REDIRECT_ASSIGNMENT 6
95 #define WCCP2_QUERY_INFO 7
96 #define WCCP2_CAPABILITY_INFO 8
97 #define WCCP2_ALT_ASSIGNMENT 13
98 #define WCCP2_ASSIGN_MAP 14
99 #define WCCP2_COMMAND_EXTENSION 15
101 /** \interface WCCPv2_Protocol
102 * Sect 5.5 WCCP Message Header
104 struct wccp2_message_header_t
{
107 #define WCCP2_VERSION 0x200
111 static struct wccp2_message_header_t wccp2_here_i_am_header
;
114 #define WCCP2_HERE_I_AM 10
115 #define WCCP2_I_SEE_YOU 11
116 #define WCCP2_REDIRECT_ASSIGN 12
117 #define WCCP2_REMOVAL_QUERY 13
119 /** \interface WCCPv2_Protocol
120 * Sect 5.6.1 Security Info Component
122 * Basic security Header. Matches "no security" case exactly.
124 struct wccp2_security_none_t
{
125 uint16_t security_type
;
126 uint16_t security_length
;
127 uint32_t security_option
;
130 /* security options */
131 #define WCCP2_NO_SECURITY 0
132 #define WCCP2_MD5_SECURITY 1
134 /** \interface WCCPv2_Protocol
135 * Sect 5.6.1 Security Info Component
137 * Extended security section. Matches "MD5 security" type exactly.
138 * Including the security header.
140 struct wccp2_security_md5_t
{
141 uint16_t security_type
;
142 uint16_t security_length
;
143 uint32_t security_option
;
144 uint8_t security_implementation
[WCCP2_MD5_SECURITY_LEN
];
147 /* Service info struct */
149 /** \interface WCCPv2_Protocol
150 * Sect 5.6.2 Service Info Component
152 struct wccp2_service_info_t
{
153 uint16_t service_type
;
154 uint16_t service_length
;
157 uint8_t service_priority
;
158 uint8_t service_protocol
;
159 uint32_t service_flags
;
170 #define WCCP2_SERVICE_STANDARD 0
171 #define WCCP2_SERVICE_DYNAMIC 1
174 #define WCCP2_SERVICE_ID_HTTP 0x00
177 #define WCCP2_SERVICE_SRC_IP_HASH 0x1
178 #define WCCP2_SERVICE_DST_IP_HASH 0x2
179 #define WCCP2_SERVICE_SRC_PORT_HASH 0x4
180 #define WCCP2_SERVICE_DST_PORT_HASH 0x8
181 #define WCCP2_SERVICE_PORTS_DEFINED 0x10
182 #define WCCP2_SERVICE_PORTS_SOURCE 0x20
183 #define WCCP2_SERVICE_SRC_IP_ALT_HASH 0x100
184 #define WCCP2_SERVICE_DST_IP_ALT_HASH 0x200
185 #define WCCP2_SERVICE_SRC_PORT_ALT_HASH 0x400
186 #define WCCP2_SERVICE_DST_PORT_ALT_HASH 0x800
188 /* TODO the following structures need to be re-defined for correct full operation.
189 wccp2_cache_identity_element needs to be merged as a sub-struct of
190 wccp2_identity_info_t (identity_type); which frees up the identifty info
191 structures so mask_assigment_data_element can become variable length
192 and cope with multiple fail-over caches hanging off one router.
195 /** \interface WCCPv2_Protocol
196 * Sect 5.7.2 Web-Cache Identity Element
198 struct wccp2_cache_identity_info_t
{
200 uint16_t hash_revision
;
202 //#define WCCP2_HASH_ASSIGNMENT_DATA 0x0
204 /* 5.7.2 Hash Assignment Data Element */
205 char buckets
[32]; /* Draft indicates 8x 32-bit buckets but it's just a mask so doesn't matter how we define. */
210 /** \interface WCCPv2_Protocol
211 * Sect 5.6.4 Web-Cache Identity Info Component
213 struct wccp2_identity_info_t
{
214 uint16_t cache_identity_type
;
215 uint16_t cache_identity_length
;
217 struct wccp2_cache_identity_info_t cache_identity
;
220 static struct wccp2_identity_info_t wccp2_identity_info
;
222 /** \interface WCCPv2_Protocol
223 * Sect 5.7.7 Mask Element
225 struct wccp2_mask_element_t
{
226 uint32_t source_ip_mask
;
227 uint32_t dest_ip_mask
;
228 uint16_t source_port_mask
;
229 uint16_t dest_port_mask
;
230 uint32_t number_values
;
233 /** \interface WCCPv2_Protocol
234 * Sect 5.7.2 Web-Cache Identity Element
236 struct wccp2_cache_mask_identity_info_t
{
238 uint16_t hash_revision
;
240 #define WCCP2_MASK_ASSIGNMENT_DATA (0x2)
242 /* Sect 5.7.2 Mask Assignment Data Element
244 * NP: draft specifies a variable-length set of keys here.
245 * the following fields only matche the special case Squid sends outbound (single-cache).
247 uint32_t mask_element_count
;
249 /* Sect 5.7.6 Mask/Value Set Element */
250 /* special case: single mask element. no values. */
251 struct wccp2_mask_element_t mask
;
253 /* Sect 5.7.2 Mask Assignment Data Element */
258 /** \interface WCCPv2_Protocol
259 * Sect 5.6.4 Web-Cache Identity Info Component
261 struct wccp2_mask_identity_info_t
{
262 uint16_t cache_identity_type
;
263 uint16_t cache_identity_length
;
265 struct wccp2_cache_mask_identity_info_t cache_identity
;
268 static struct wccp2_mask_identity_info_t wccp2_mask_identity_info
;
270 /** \interface WCCPv2_Protocol
271 * Sect 5.6.5 Router View Info Component
272 * Sect 5.6.6 Web Cache View Info Component
274 * first three fields. (shared by both view components)
276 struct wccp2_cache_view_header_t
{
277 uint16_t cache_view_type
;
278 uint16_t cache_view_length
;
279 uint32_t cache_view_version
;
282 static struct wccp2_cache_view_header_t wccp2_cache_view_header
;
284 /// \interface WCCPv2_Protocol
285 /* NP: special-case 5.6.5 or 5.6.6 * View Info when no routers or caches are advertised? */
286 struct wccp2_cache_view_info_t
{
287 uint32_t num_routers
;
291 static struct wccp2_cache_view_info_t wccp2_cache_view_info
;
293 /** \interface WCCPv2_Protocol
294 * Sect 5.7.1 Router ID Element
296 struct wccp2_router_id_element_t
{
297 struct in_addr router_address
;
298 uint32_t received_id
;
301 static struct wccp2_router_id_element_t wccp2_router_id_element
;
303 /** \interface WCCPv2_Protocol
304 * Sect 5.6.9 Capabilities Info Component
306 struct wccp2_capability_info_header_t
{
307 uint16_t capability_info_type
;
308 uint16_t capability_info_length
;
309 /* dynamic length capabilities list */
312 static struct wccp2_capability_info_header_t wccp2_capability_info_header
;
314 /** \interface WCCPv2_Protocol
315 * 5.7.5 Capability Element
317 struct wccp2_capability_element_t
{
318 uint16_t capability_type
;
319 uint16_t capability_length
;
320 uint32_t capability_value
;
322 static struct wccp2_capability_element_t wccp2_capability_element
;
324 /* capability types */
325 #define WCCP2_CAPABILITY_FORWARDING_METHOD 0x01
326 #define WCCP2_CAPABILITY_ASSIGNMENT_METHOD 0x02
327 #define WCCP2_CAPABILITY_RETURN_METHOD 0x03
328 // 0x04 ?? - advertised by a 4507 (ios v15.1) Cisco switch
329 // 0x05 ?? - advertised by a 4507 (ios v15.1) Cisco switch
331 /* capability values */
332 #define WCCP2_METHOD_GRE 0x00000001
333 #define WCCP2_METHOD_L2 0x00000002
334 /* when type=WCCP2_CAPABILITY_FORWARDING_METHOD */
335 #define WCCP2_FORWARDING_METHOD_GRE WCCP2_METHOD_GRE
336 #define WCCP2_FORWARDING_METHOD_L2 WCCP2_METHOD_L2
337 /* when type=WCCP2_CAPABILITY_ASSIGNMENT_METHOD */
338 #define WCCP2_ASSIGNMENT_METHOD_HASH 0x00000001
339 #define WCCP2_ASSIGNMENT_METHOD_MASK 0x00000002
340 /* when type=WCCP2_CAPABILITY_RETURN_METHOD */
341 #define WCCP2_PACKET_RETURN_METHOD_GRE WCCP2_METHOD_GRE
342 #define WCCP2_PACKET_RETURN_METHOD_L2 WCCP2_METHOD_L2
344 /** \interface WCCPv2_Protocol
345 * 5.7.8 Value Element
347 struct wccp2_value_element_t
{
348 uint32_t source_ip_value
;
349 uint32_t dest_ip_value
;
350 uint16_t source_port_value
;
351 uint16_t dest_port_value
;
353 struct in_addr cache_ip
;
356 /* RECEIVED PACKET STRUCTURE */
358 /** \interface WCCPv2_Protocol
359 * 5.2 'I See You' Message
361 struct wccp2_i_see_you_t
{
365 char data
[WCCP_RESPONSE_SIZE
];
368 static struct wccp2_i_see_you_t wccp2_i_see_you
;
370 /** \interface WCCPv2_Protocol
371 * 5.7.4 Router Assignment Element
373 struct wccp2_router_assign_element_t
{
374 struct in_addr router_address
;
375 uint32_t received_id
;
376 uint32_t change_number
;
379 /* Router identity struct */
381 /** \interface WCCPv2_Protocol
382 * 5.6.3 Router Identity Info Component (partial)
384 struct router_identity_info_t
{
386 struct wccp2_item_header_t header
;
388 struct wccp2_router_id_element_t router_id_element
;
390 struct in_addr router_address
;
391 uint32_t number_caches
;
392 /* dynamic list of cache IP addresses */
395 /* The received packet for a mask assignment is unusual */
397 /** \interface WCCPv2_Protocol
398 * Sect 5.7.7 Mask Element ???
399 * see code below. apparently the supposed IP address at position num1 can be equal to 3.
401 struct cache_mask_info_t
{
408 /** \interface WCCPv2_Protocol
409 * 5.7.3 Assignment Key Element
411 struct assignment_key_t
{
412 struct in_addr master_ip
;
413 uint32_t master_number
;
416 /** \interface WCCPv2_Protocol
417 * 5.6.5 Router View Info Component (first three fields)
419 struct router_view_t
{
420 struct wccp2_item_header_t header
;
421 uint32_t change_number
;
422 struct assignment_key_t assignment_key
;
423 /* dynamic lists of routers and caches elided */
426 /* Lists used to keep track of caches, routers and services */
428 /// \interface WCCPv2_Protocol
429 struct wccp2_cache_list_t
{
431 struct in_addr cache_ip
;
435 struct wccp2_cache_list_t
*next
;
438 /// \interface WCCPv2_Protocol
439 struct wccp2_router_list_t
{
441 struct wccp2_router_id_element_t
*info
;
443 struct in_addr local_ip
;
445 struct in_addr router_sendto_address
;
446 uint32_t member_change
;
449 struct wccp2_cache_list_t cache_list_head
;
451 struct wccp2_router_list_t
*next
;
454 static int wccp2_numrouters
;
456 /// \interface WCCPv2_Protocol
457 struct wccp2_service_list_t
{
459 struct wccp2_service_info_t info
;
460 uint32_t num_routers
;
462 struct wccp2_router_list_t router_list_head
;
466 char *wccp2_identity_info_ptr
;
468 struct wccp2_security_md5_t
*security_info
;
470 struct wccp2_service_info_t
*service_info
;
471 char wccp_packet
[WCCP_RESPONSE_SIZE
];
472 size_t wccp_packet_size
;
474 struct wccp2_service_list_t
*next
;
475 char wccp_password
[WCCP2_PASSWORD_LEN
+ 1]; /* hold the trailing C-string NUL */
476 uint32_t wccp2_security_type
;
479 static struct wccp2_service_list_t
*wccp2_service_list_head
= NULL
;
481 int empty_portlist
[WCCP2_NUMPORTS
] = {0, 0, 0, 0, 0, 0, 0, 0};
483 /* END WCCP V2 PROTOCL TYPES DEFINITION */
485 void wccp2_add_service_list(int service
, int service_id
, int service_priority
,
486 int service_proto
, int service_flags
, int ports
[], int security_type
, char *password
);
487 static void wccp2SortCacheList(struct wccp2_cache_list_t
*head
);
490 * The functions used during startup:
492 * wccp2ConnectionOpen
493 * wccp2ConnectionClose
497 wccp2InitServices(void)
499 debugs(80, 5, "wccp2InitServices: called");
503 wccp2_update_service(struct wccp2_service_list_t
*srv
, int service
,
504 int service_id
, int service_priority
, int service_proto
, int service_flags
,
507 /* XXX check what needs to be wrapped in htons()! */
508 srv
->info
.service
= service
;
509 srv
->info
.service_id
= service_id
;
510 srv
->info
.service_priority
= service_priority
;
511 srv
->info
.service_protocol
= service_proto
;
512 srv
->info
.service_flags
= htonl(service_flags
);
513 srv
->info
.port0
= htons(ports
[0]);
514 srv
->info
.port1
= htons(ports
[1]);
515 srv
->info
.port2
= htons(ports
[2]);
516 srv
->info
.port3
= htons(ports
[3]);
517 srv
->info
.port4
= htons(ports
[4]);
518 srv
->info
.port5
= htons(ports
[5]);
519 srv
->info
.port6
= htons(ports
[6]);
520 srv
->info
.port7
= htons(ports
[7]);
524 wccp2_add_service_list(int service
, int service_id
, int service_priority
,
525 int service_proto
, int service_flags
, int ports
[], int security_type
,
529 struct wccp2_service_list_t
*wccp2_service_list_ptr
;
531 wccp2_service_list_ptr
= (wccp2_service_list_t
*) xcalloc(1, sizeof(struct wccp2_service_list_t
));
533 debugs(80, 5, "wccp2_add_service_list: added service id " << service_id
);
535 /* XXX check what needs to be wrapped in htons()! */
536 wccp2_service_list_ptr
->info
.service_type
= htons(WCCP2_SERVICE_INFO
);
538 wccp2_service_list_ptr
->info
.service_length
= htons(sizeof(struct wccp2_service_info_t
) - 4);
539 wccp2_service_list_ptr
->change_num
= 0;
540 wccp2_update_service(wccp2_service_list_ptr
, service
, service_id
,
541 service_priority
, service_proto
, service_flags
, ports
);
542 wccp2_service_list_ptr
->wccp2_security_type
= security_type
;
543 memset(wccp2_service_list_ptr
->wccp_password
, 0, WCCP2_PASSWORD_LEN
+ 1);
544 strncpy(wccp2_service_list_ptr
->wccp_password
, password
, WCCP2_PASSWORD_LEN
);
545 /* add to linked list - XXX this should use the Squid dlink* routines! */
546 wccp2_service_list_ptr
->next
= wccp2_service_list_head
;
547 wccp2_service_list_head
= wccp2_service_list_ptr
;
550 static struct wccp2_service_list_t
*
551 wccp2_get_service_by_id(int service
, int service_id
) {
553 struct wccp2_service_list_t
*p
;
555 p
= wccp2_service_list_head
;
558 if (p
->info
.service
== service
&& p
->info
.service_id
== service_id
) {
569 * Update the md5 security header, if possible
571 * Returns: 1 if we set it, 0 if not (eg, no security section, or non-md5)
574 wccp2_update_md5_security(char *password
, char *ptr
, char *packet
, int len
)
576 uint8_t md5Digest
[SQUID_MD5_DIGEST_LENGTH
];
577 char pwd
[WCCP2_PASSWORD_LEN
];
580 struct wccp2_security_md5_t
*ws
;
582 debugs(80, 5, "wccp2_update_md5_security: called");
584 /* The password field, for the MD5 hash, needs to be 8 bytes and NUL padded. */
585 memset(pwd
, 0, sizeof(pwd
));
586 strncpy(pwd
, password
, sizeof(pwd
));
587 pwd
[sizeof(pwd
) - 1] = '\0';
589 ws
= (struct wccp2_security_md5_t
*) ptr
;
590 assert(ntohs(ws
->security_type
) == WCCP2_SECURITY_INFO
);
591 /* Its the security part */
593 if (ntohl(ws
->security_option
) != WCCP2_MD5_SECURITY
) {
594 debugs(80, 5, "wccp2_update_md5_security: this service ain't md5'ing, abort");
598 /* And now its the MD5 section! */
599 /* According to the draft, the MD5 security hash is the combination of
600 * the 8-octet password (padded w/ NUL bytes) and the entire WCCP packet,
601 * including the WCCP message header. The WCCP security implementation
602 * area should be zero'ed before calculating the MD5 hash.
604 /* XXX eventually we should be able to kill md5Digest and blit it directly in */
605 memset(ws
->security_implementation
, 0, sizeof(ws
->security_implementation
));
609 SquidMD5Update(&M
, pwd
, sizeof(pwd
));
611 SquidMD5Update(&M
, packet
, len
);
613 SquidMD5Final(md5Digest
, &M
);
615 memcpy(ws
->security_implementation
, md5Digest
, sizeof(md5Digest
));
622 * Check the given WCCP2 packet against the given password.
626 wccp2_check_security(struct wccp2_service_list_t
*srv
, char *security
, char *packet
, int len
)
629 struct wccp2_security_md5_t
*ws
= (struct wccp2_security_md5_t
*) security
;
630 uint8_t md5Digest
[SQUID_MD5_DIGEST_LENGTH
], md5_challenge
[SQUID_MD5_DIGEST_LENGTH
];
631 char pwd
[WCCP2_PASSWORD_LEN
];
634 /* Make sure the security type matches what we expect */
636 if (ntohl(ws
->security_option
) != srv
->wccp2_security_type
) {
637 debugs(80, DBG_IMPORTANT
, "wccp2_check_security: received packet has the wrong security option");
641 if (srv
->wccp2_security_type
== WCCP2_NO_SECURITY
) {
645 if (srv
->wccp2_security_type
!= WCCP2_MD5_SECURITY
) {
646 debugs(80, DBG_IMPORTANT
, "wccp2_check_security: invalid security option");
650 /* If execution makes it here then we have an MD5 security */
652 /* The password field, for the MD5 hash, needs to be 8 bytes and NUL padded. */
653 memset(pwd
, 0, sizeof(pwd
));
654 strncpy(pwd
, srv
->wccp_password
, sizeof(pwd
));
655 pwd
[sizeof(pwd
) - 1] = '\0';
657 /* Take a copy of the challenge: we need to NUL it before comparing */
658 memcpy(md5_challenge
, ws
->security_implementation
, sizeof(md5_challenge
));
660 memset(ws
->security_implementation
, 0, sizeof(ws
->security_implementation
));
664 SquidMD5Update(&M
, pwd
, sizeof(pwd
));
666 SquidMD5Update(&M
, packet
, len
);
668 SquidMD5Final(md5Digest
, &M
);
670 return (memcmp(md5Digest
, md5_challenge
, SQUID_MD5_DIGEST_LENGTH
) == 0);
678 uint32_t service_flags
;
680 struct wccp2_service_list_t
*service_list_ptr
;
682 struct wccp2_router_list_t
*router_list_ptr
;
684 debugs(80, 5, "wccp2Init: Called");
686 if (wccp2_connected
== 1)
689 wccp2_numrouters
= 0;
691 /* Calculate the number of routers configured in the config file */
692 for (s
= Config
.Wccp2
.router
; s
; s
= s
->next
) {
693 if (!s
->s
.isAnyAddr()) {
694 /* Increment the counter */
699 if (wccp2_numrouters
== 0) {
703 struct wccp2_security_md5_t wccp2_security_md5
;
704 memset(&wccp2_security_md5
, 0, sizeof(wccp2_security_md5
));
706 /* Initialise the list of services */
709 service_list_ptr
= wccp2_service_list_head
;
711 while (service_list_ptr
!= NULL
) {
712 /* Set up our list pointers */
713 router_list_ptr
= &service_list_ptr
->router_list_head
;
715 /* start the wccp header */
716 wccp2_here_i_am_header
.type
= htonl(WCCP2_HERE_I_AM
);
717 wccp2_here_i_am_header
.version
= htons(WCCP2_VERSION
);
718 wccp2_here_i_am_header
.length
= 0;
719 ptr
= service_list_ptr
->wccp_packet
+ sizeof(wccp2_here_i_am_header
);
721 /* add the security section */
722 /* XXX this is ugly */
724 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
725 wccp2_security_md5
.security_option
= htonl(WCCP2_MD5_SECURITY
);
727 wccp2_security_md5
.security_length
= htons(sizeof(struct wccp2_security_md5_t
) - 4);
728 } else if (service_list_ptr
->wccp2_security_type
== WCCP2_NO_SECURITY
) {
729 wccp2_security_md5
.security_option
= htonl(WCCP2_NO_SECURITY
);
730 /* XXX I hate magic length numbers! */
731 wccp2_security_md5
.security_length
= htons(4);
733 fatalf("Bad WCCP2 security type\n");
736 wccp2_here_i_am_header
.length
+= ntohs(wccp2_security_md5
.security_length
) + 4;
737 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
738 wccp2_security_md5
.security_type
= htons(WCCP2_SECURITY_INFO
);
740 service_list_ptr
->security_info
= (struct wccp2_security_md5_t
*) ptr
;
742 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
743 memcpy(ptr
, &wccp2_security_md5
, sizeof(struct wccp2_security_md5_t
));
744 ptr
+= sizeof(struct wccp2_security_md5_t
);
746 /* assume NONE, and XXX I hate magic length numbers */
747 memcpy(ptr
, &wccp2_security_md5
, 8);
751 /* Add the service info section */
753 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_service_info_t
);
755 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
757 memcpy(ptr
, &service_list_ptr
->info
, sizeof(struct wccp2_service_info_t
));
759 service_list_ptr
->service_info
= (struct wccp2_service_info_t
*) ptr
;
761 ptr
+= sizeof(struct wccp2_service_info_t
);
763 /* Add the cache identity section */
765 switch (Config
.Wccp2
.assignment_method
) {
767 case WCCP2_ASSIGNMENT_METHOD_HASH
:
769 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_identity_info_t
);
770 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
771 wccp2_identity_info
.cache_identity_type
= htons(WCCP2_WC_ID_INFO
);
772 wccp2_identity_info
.cache_identity_length
= htons(sizeof(wccp2_identity_info
.cache_identity
));
773 memset(&wccp2_identity_info
.cache_identity
.addr
, '\0', sizeof(struct in_addr
));
774 memset(&wccp2_identity_info
.cache_identity
.hash_revision
, '\0', sizeof(wccp2_identity_info
.cache_identity
.hash_revision
));
775 memset(&wccp2_identity_info
.cache_identity
.bits
, '\0', sizeof(wccp2_identity_info
.cache_identity
.bits
));
776 memset(&wccp2_identity_info
.cache_identity
.buckets
, '\0', sizeof(wccp2_identity_info
.cache_identity
.buckets
));
777 wccp2_identity_info
.cache_identity
.weight
= htons(Config
.Wccp2
.weight
);
778 memset(&wccp2_identity_info
.cache_identity
.status
, '\0', sizeof(wccp2_identity_info
.cache_identity
.status
));
780 memcpy(ptr
, &wccp2_identity_info
, sizeof(struct wccp2_identity_info_t
));
781 service_list_ptr
->wccp2_identity_info_ptr
= ptr
;
783 ptr
+= sizeof(struct wccp2_identity_info_t
);
786 case WCCP2_ASSIGNMENT_METHOD_MASK
:
788 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_mask_identity_info_t
);
789 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
790 wccp2_mask_identity_info
.cache_identity_type
= htons(WCCP2_WC_ID_INFO
);
791 wccp2_mask_identity_info
.cache_identity_length
= htons(sizeof(wccp2_mask_identity_info
.cache_identity
));
792 memset(&wccp2_mask_identity_info
.cache_identity
.addr
, '\0', sizeof(struct in_addr
));
793 wccp2_mask_identity_info
.cache_identity
.bits
= htons(WCCP2_MASK_ASSIGNMENT_DATA
);
794 wccp2_mask_identity_info
.cache_identity
.mask_element_count
= htonl(1);
795 service_flags
= ntohl(service_list_ptr
->service_info
->service_flags
);
797 memset(&wccp2_mask_identity_info
.cache_identity
.mask
, 0, sizeof(struct wccp2_mask_element_t
));
799 if ((service_flags
& WCCP2_SERVICE_SRC_IP_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
)) {
800 wccp2_mask_identity_info
.cache_identity
.mask
.source_ip_mask
= htonl(0x00001741);
801 } 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
)) {
802 wccp2_mask_identity_info
.cache_identity
.mask
.dest_ip_mask
= htonl(0x00001741);
803 } else if ((service_flags
& WCCP2_SERVICE_SRC_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
)) {
804 wccp2_mask_identity_info
.cache_identity
.mask
.source_port_mask
= htons(0x1741);
805 } else if ((service_flags
& WCCP2_SERVICE_DST_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
)) {
806 wccp2_mask_identity_info
.cache_identity
.mask
.dest_port_mask
= htons(0x1741);
808 fatalf("Unknown service hash method\n");
811 wccp2_mask_identity_info
.cache_identity
.weight
= 0;
812 wccp2_mask_identity_info
.cache_identity
.status
= 0;
814 memcpy(ptr
, &wccp2_mask_identity_info
, sizeof(struct wccp2_mask_identity_info_t
));
815 service_list_ptr
->wccp2_identity_info_ptr
= ptr
;
817 ptr
+= sizeof(struct wccp2_mask_identity_info_t
);
821 fatalf("Unknown Wccp2 assignment method\n");
824 /* Add the cache view section */
825 wccp2_here_i_am_header
.length
+= sizeof(wccp2_cache_view_header
);
827 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
829 wccp2_cache_view_header
.cache_view_type
= htons(WCCP2_WC_VIEW_INFO
);
831 wccp2_cache_view_header
.cache_view_length
= htons(sizeof(wccp2_cache_view_header
) - 4 +
832 sizeof(wccp2_cache_view_info
) + (wccp2_numrouters
* sizeof(wccp2_router_id_element
)));
834 wccp2_cache_view_header
.cache_view_version
= htonl(1);
836 memcpy(ptr
, &wccp2_cache_view_header
, sizeof(wccp2_cache_view_header
));
838 ptr
+= sizeof(wccp2_cache_view_header
);
840 /* Add the number of routers to the packet */
841 wccp2_here_i_am_header
.length
+= sizeof(service_list_ptr
->num_routers
);
843 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
845 service_list_ptr
->num_routers
= htonl(wccp2_numrouters
);
847 memcpy(ptr
, &service_list_ptr
->num_routers
, sizeof(service_list_ptr
->num_routers
));
849 ptr
+= sizeof(service_list_ptr
->num_routers
);
851 /* Add each router. Keep this functionality here to make sure the received_id can be updated in the packet */
852 for (s
= Config
.Wccp2
.router
; s
; s
= s
->next
) {
853 if (!s
->s
.isAnyAddr()) {
855 wccp2_here_i_am_header
.length
+= sizeof(struct wccp2_router_id_element_t
);
856 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
858 /* Add a pointer to the router list for this router */
860 router_list_ptr
->info
= (struct wccp2_router_id_element_t
*) ptr
;
861 s
->s
.getInAddr(router_list_ptr
->info
->router_address
);
862 router_list_ptr
->info
->received_id
= htonl(0);
863 s
->s
.getInAddr(router_list_ptr
->router_sendto_address
);
864 router_list_ptr
->member_change
= htonl(0);
866 /* Build the next struct */
868 router_list_ptr
->next
= (wccp2_router_list_t
*) xcalloc(1, sizeof(struct wccp2_router_list_t
));
870 /* update the pointer */
871 router_list_ptr
= router_list_ptr
->next
;
872 router_list_ptr
->next
= NULL
;
874 /* no need to copy memory - we've just set the values directly in the packet above */
876 ptr
+= sizeof(struct wccp2_router_id_element_t
);
880 /* Add the number of caches (0) */
881 wccp2_here_i_am_header
.length
+= sizeof(wccp2_cache_view_info
.num_caches
);
883 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
885 wccp2_cache_view_info
.num_caches
= htonl(0);
887 memcpy(ptr
, &wccp2_cache_view_info
.num_caches
, sizeof(wccp2_cache_view_info
.num_caches
));
889 ptr
+= sizeof(wccp2_cache_view_info
.num_caches
);
891 /* Add the extra capability header */
892 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_info_header
);
894 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
896 wccp2_capability_info_header
.capability_info_type
= htons(WCCP2_CAPABILITY_INFO
);
898 wccp2_capability_info_header
.capability_info_length
= htons(3 * sizeof(wccp2_capability_element
));
900 memcpy(ptr
, &wccp2_capability_info_header
, sizeof(wccp2_capability_info_header
));
902 ptr
+= sizeof(wccp2_capability_info_header
);
904 /* Add the forwarding method */
905 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_element
);
907 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
909 wccp2_capability_element
.capability_type
= htons(WCCP2_CAPABILITY_FORWARDING_METHOD
);
911 wccp2_capability_element
.capability_length
= htons(sizeof(wccp2_capability_element
.capability_value
));
913 wccp2_capability_element
.capability_value
= htonl(Config
.Wccp2
.forwarding_method
);
915 memcpy(ptr
, &wccp2_capability_element
, sizeof(wccp2_capability_element
));
917 ptr
+= sizeof(wccp2_capability_element
);
919 /* Add the assignment method */
920 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_element
);
922 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
924 wccp2_capability_element
.capability_type
= htons(WCCP2_CAPABILITY_ASSIGNMENT_METHOD
);
926 wccp2_capability_element
.capability_length
= htons(sizeof(wccp2_capability_element
.capability_value
));
928 wccp2_capability_element
.capability_value
= htonl(Config
.Wccp2
.assignment_method
);
930 memcpy(ptr
, &wccp2_capability_element
, sizeof(wccp2_capability_element
));
932 ptr
+= sizeof(wccp2_capability_element
);
934 /* Add the return method */
935 wccp2_here_i_am_header
.length
+= sizeof(wccp2_capability_element
);
937 assert(wccp2_here_i_am_header
.length
<= WCCP_RESPONSE_SIZE
);
939 wccp2_capability_element
.capability_type
= htons(WCCP2_CAPABILITY_RETURN_METHOD
);
941 wccp2_capability_element
.capability_length
= htons(sizeof(wccp2_capability_element
.capability_value
));
943 wccp2_capability_element
.capability_value
= htonl(Config
.Wccp2
.return_method
);
945 memcpy(ptr
, &wccp2_capability_element
, sizeof(wccp2_capability_element
));
947 ptr
+= sizeof(wccp2_capability_element
);
949 /* Finally, fix the total length to network order, and copy to the appropriate memory blob */
950 wccp2_here_i_am_header
.length
= htons(wccp2_here_i_am_header
.length
);
952 memcpy(&service_list_ptr
->wccp_packet
, &wccp2_here_i_am_header
, sizeof(wccp2_here_i_am_header
));
954 service_list_ptr
->wccp_packet_size
= ntohs(wccp2_here_i_am_header
.length
) + sizeof(wccp2_here_i_am_header
);
956 /* Add the event if everything initialised correctly */
957 debugs(80,3,"wccp2Init: scheduled 'HERE_I_AM' message to " << wccp2_numrouters
<< "routers.");
958 if (wccp2_numrouters
) {
959 if (!eventFind(wccp2HereIam
, NULL
)) {
960 eventAdd("wccp2HereIam", wccp2HereIam
, NULL
, 1, 1);
962 debugs(80,3,"wccp2Init: skip duplicate 'HERE_I_AM'.");
965 service_list_ptr
= service_list_ptr
->next
;
970 wccp2ConnectionOpen(void)
972 struct sockaddr_in router
, local
, null
;
973 socklen_t local_len
, router_len
;
975 struct wccp2_service_list_t
*service_list_ptr
;
977 struct wccp2_router_list_t
*router_list_ptr
;
979 debugs(80, 5, "wccp2ConnectionOpen: Called");
981 if (wccp2_numrouters
== 0 || !wccp2_service_list_head
) {
982 debugs(80, 2, "WCCPv2 Disabled. No IPv4 Router(s) configured.");
986 if ( !Config
.Wccp2
.address
.setIPv4() ) {
987 debugs(80, DBG_CRITICAL
, "WCCPv2 Disabled. Local address " << Config
.Wccp2
.address
<< " is not an IPv4 address.");
991 Config
.Wccp2
.address
.port(WCCP_PORT
);
992 theWccp2Connection
= comm_open_listener(SOCK_DGRAM
,
994 Config
.Wccp2
.address
,
998 if (theWccp2Connection
< 0)
999 fatal("Cannot open WCCP Port");
1001 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1003 int i
= IP_PMTUDISC_DONT
;
1004 if (setsockopt(theWccp2Connection
, SOL_IP
, IP_MTU_DISCOVER
, &i
, sizeof i
) < 0)
1005 debugs(80, 2, "WARNING: Path MTU discovery could not be disabled on FD " << theWccp2Connection
<< ": " << xstrerror());
1009 Comm::SetSelect(theWccp2Connection
, COMM_SELECT_READ
, wccp2HandleUdp
, NULL
, 0);
1011 debugs(80, DBG_IMPORTANT
, "Accepting WCCPv2 messages on port " << WCCP_PORT
<< ", FD " << theWccp2Connection
<< ".");
1012 debugs(80, DBG_IMPORTANT
, "Initialising all WCCPv2 lists");
1014 /* Initialise all routers on all services */
1015 memset(&null
, 0, sizeof(null
));
1017 null
.sin_family
= AF_UNSPEC
;
1019 service_list_ptr
= wccp2_service_list_head
;
1021 while (service_list_ptr
!= NULL
) {
1022 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1023 router_len
= sizeof(router
);
1024 memset(&router
, '\0', router_len
);
1025 router
.sin_family
= AF_INET
;
1026 router
.sin_port
= htons(WCCP_PORT
);
1027 router
.sin_addr
= router_list_ptr
->router_sendto_address
;
1029 if (connect(theWccp2Connection
, (struct sockaddr
*) &router
, router_len
))
1030 fatal("Unable to connect WCCP out socket");
1032 local_len
= sizeof(local
);
1034 memset(&local
, '\0', local_len
);
1036 if (getsockname(theWccp2Connection
, (struct sockaddr
*) &local
, &local_len
))
1037 fatal("Unable to getsockname on WCCP out socket");
1039 router_list_ptr
->local_ip
= local
.sin_addr
;
1041 /* Disconnect the sending socket. Note: FreeBSD returns error
1042 * but disconnects anyway so we have to just assume it worked
1044 if (wccp2_numrouters
> 1) {
1045 (void)connect(theWccp2Connection
, (struct sockaddr
*) &null
, router_len
);
1049 service_list_ptr
= service_list_ptr
->next
;
1052 wccp2_connected
= 1;
1056 wccp2ConnectionClose(void)
1059 struct wccp2_service_list_t
*service_list_ptr
;
1061 struct wccp2_service_list_t
*service_list_ptr_next
;
1063 struct wccp2_router_list_t
*router_list_ptr
;
1065 struct wccp2_router_list_t
*router_list_next
;
1067 struct wccp2_cache_list_t
*cache_list_ptr
;
1069 struct wccp2_cache_list_t
*cache_list_ptr_next
;
1071 if (wccp2_connected
== 0) {
1075 if (theWccp2Connection
> -1) {
1076 debugs(80, DBG_IMPORTANT
, "FD " << theWccp2Connection
<< " Closing WCCPv2 socket");
1077 comm_close(theWccp2Connection
);
1078 theWccp2Connection
= -1;
1081 /* for each router on each service send a packet */
1082 service_list_ptr
= wccp2_service_list_head
;
1084 while (service_list_ptr
!= NULL
) {
1085 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
!= NULL
; router_list_ptr
= router_list_next
) {
1086 for (cache_list_ptr
= &router_list_ptr
->cache_list_head
; cache_list_ptr
; cache_list_ptr
= cache_list_ptr_next
) {
1087 cache_list_ptr_next
= cache_list_ptr
->next
;
1089 if (cache_list_ptr
!= &router_list_ptr
->cache_list_head
) {
1090 xfree(cache_list_ptr
);
1093 memset(cache_list_ptr
, '\0', sizeof(struct wccp2_cache_list_t
));
1097 router_list_next
= router_list_ptr
->next
;
1099 if (router_list_ptr
!= &service_list_ptr
->router_list_head
) {
1100 xfree(router_list_ptr
);
1103 memset(router_list_ptr
, '\0', sizeof(struct wccp2_router_list_t
));
1107 service_list_ptr_next
= service_list_ptr
->next
;
1108 xfree(service_list_ptr
);
1109 service_list_ptr
= service_list_ptr_next
;
1112 wccp2_service_list_head
= NULL
;
1113 eventDelete(wccp2HereIam
, NULL
);
1114 eventDelete(wccp2AssignBuckets
, NULL
);
1115 eventDelete(wccp2HereIam
, NULL
);
1116 wccp2_connected
= 0;
1120 * Functions for handling the requests.
1124 * Accept the UDP packet
1127 wccp2HandleUdp(int sock
, void *not_used
)
1130 struct wccp2_service_list_t
*service_list_ptr
;
1132 struct wccp2_router_list_t
*router_list_ptr
;
1134 struct wccp2_cache_list_t
*cache_list_ptr
;
1136 struct wccp2_cache_list_t
*cache_list_ptr_next
;
1138 /* These structs form the parts of the packet */
1140 struct wccp2_item_header_t
*header
= NULL
;
1142 struct wccp2_security_none_t
*security_info
= NULL
;
1144 struct wccp2_service_info_t
*service_info
= NULL
;
1146 struct router_identity_info_t
*router_identity_info
= NULL
;
1148 struct router_view_t
*router_view_header
= NULL
;
1150 struct wccp2_cache_mask_identity_info_t
*cache_mask_identity
= NULL
;
1152 struct cache_mask_info_t
*cache_mask_info
= NULL
;
1154 struct wccp2_cache_identity_info_t
*cache_identity
= NULL
;
1156 struct wccp2_capability_info_header_t
*router_capability_header
= NULL
;
1158 struct wccp2_capability_element_t
*router_capability_element
;
1160 struct sockaddr_in from
;
1162 struct in_addr cache_address
;
1164 short int data_length
, offset
;
1169 debugs(80, 6, "wccp2HandleUdp: Called.");
1171 Comm::SetSelect(sock
, COMM_SELECT_READ
, wccp2HandleUdp
, NULL
, 0);
1173 /* FIXME INET6 : drop conversion boundary */
1174 Ip::Address from_tmp
;
1177 len
= comm_udp_recvfrom(sock
,
1186 if (ntohs(wccp2_i_see_you
.version
) != WCCP2_VERSION
)
1189 if (ntohl(wccp2_i_see_you
.type
) != WCCP2_I_SEE_YOU
)
1192 /* FIXME INET6 : drop conversion boundary */
1193 from_tmp
.getSockAddr(from
);
1195 debugs(80, 3, "Incoming WCCPv2 I_SEE_YOU length " << ntohs(wccp2_i_see_you
.length
) << ".");
1197 /* Record the total data length */
1198 data_length
= ntohs(wccp2_i_see_you
.length
);
1202 if (data_length
> len
) {
1203 debugs(80, DBG_IMPORTANT
, "ERROR: Malformed WCCPv2 packet claiming it's bigger than received data");
1207 /* Go through the data structure */
1208 while (data_length
> offset
) {
1210 char *data
= wccp2_i_see_you
.data
;
1212 header
= (struct wccp2_item_header_t
*) &data
[offset
];
1214 switch (ntohs(header
->type
)) {
1216 case WCCP2_SECURITY_INFO
:
1218 if (security_info
!= NULL
) {
1219 debugs(80, DBG_IMPORTANT
, "Duplicate security definition");
1223 security_info
= (struct wccp2_security_none_t
*) &wccp2_i_see_you
.data
[offset
];
1226 case WCCP2_SERVICE_INFO
:
1228 if (service_info
!= NULL
) {
1229 debugs(80, DBG_IMPORTANT
, "Duplicate service_info definition");
1233 service_info
= (struct wccp2_service_info_t
*) &wccp2_i_see_you
.data
[offset
];
1236 case WCCP2_ROUTER_ID_INFO
:
1238 if (router_identity_info
!= NULL
) {
1239 debugs(80, DBG_IMPORTANT
, "Duplicate router_identity_info definition");
1243 router_identity_info
= (struct router_identity_info_t
*) &wccp2_i_see_you
.data
[offset
];
1246 case WCCP2_RTR_VIEW_INFO
:
1248 if (router_view_header
!= NULL
) {
1249 debugs(80, DBG_IMPORTANT
, "Duplicate router_view definition");
1253 router_view_header
= (struct router_view_t
*) &wccp2_i_see_you
.data
[offset
];
1256 case WCCP2_CAPABILITY_INFO
:
1258 if (router_capability_header
!= NULL
) {
1259 debugs(80, DBG_IMPORTANT
, "Duplicate router_capability definition");
1263 router_capability_header
= (struct wccp2_capability_info_header_t
*) &wccp2_i_see_you
.data
[offset
];
1266 /* Nothing to do for the types below */
1268 case WCCP2_ASSIGN_MAP
:
1269 case WCCP2_REDIRECT_ASSIGNMENT
:
1273 debugs(80, DBG_IMPORTANT
, "Unknown record type in WCCPv2 Packet (" << ntohs(header
->type
) << ").");
1276 offset
+= sizeof(struct wccp2_item_header_t
);
1277 offset
+= ntohs(header
->length
);
1279 if (offset
> data_length
) {
1280 debugs(80, DBG_IMPORTANT
, "Error: WCCPv2 packet tried to tell us there is data beyond the end of the packet");
1285 if ((security_info
== NULL
) || (service_info
== NULL
) || (router_identity_info
== NULL
) || (router_view_header
== NULL
)) {
1286 debugs(80, DBG_IMPORTANT
, "Incomplete WCCPv2 Packet");
1290 debugs(80, 5, "Complete packet received");
1292 /* Check that the service in the packet is configured on this router */
1293 service_list_ptr
= wccp2_service_list_head
;
1295 while (service_list_ptr
!= NULL
) {
1296 if (service_info
->service_id
== service_list_ptr
->service_info
->service_id
) {
1300 service_list_ptr
= service_list_ptr
->next
;
1303 if (service_list_ptr
== NULL
) {
1304 debugs(80, DBG_IMPORTANT
, "WCCPv2 Unknown service received from router (" << service_info
->service_id
<< ")");
1308 if (ntohl(security_info
->security_option
) != ntohl(service_list_ptr
->security_info
->security_option
)) {
1309 debugs(80, DBG_IMPORTANT
, "Invalid security option in WCCPv2 Packet (" << ntohl(security_info
->security_option
) << " vs " << ntohl(service_list_ptr
->security_info
->security_option
) << ").");
1313 if (!wccp2_check_security(service_list_ptr
, (char *) security_info
, (char *) &wccp2_i_see_you
, len
)) {
1314 debugs(80, DBG_IMPORTANT
, "Received WCCPv2 Packet failed authentication");
1318 /* Check that the router address is configured on this router */
1319 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1320 if (router_list_ptr
->router_sendto_address
.s_addr
== from
.sin_addr
.s_addr
)
1324 if (router_list_ptr
->next
== NULL
) {
1325 debugs(80, DBG_IMPORTANT
, "WCCPv2 Packet received from unknown router");
1329 /* Set the router id */
1330 router_list_ptr
->info
->router_address
= router_identity_info
->router_id_element
.router_address
;
1332 /* Increment the received id in the packet */
1333 if (ntohl(router_list_ptr
->info
->received_id
) != ntohl(router_identity_info
->router_id_element
.received_id
)) {
1334 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
) << ".");
1335 router_list_ptr
->info
->received_id
= router_identity_info
->router_id_element
.received_id
;
1338 /* TODO: check return/forwarding methods */
1339 if (router_capability_header
== NULL
) {
1340 if ((Config
.Wccp2
.return_method
!= WCCP2_PACKET_RETURN_METHOD_GRE
) || (Config
.Wccp2
.forwarding_method
!= WCCP2_FORWARDING_METHOD_GRE
)) {
1341 debugs(80, DBG_IMPORTANT
, "wccp2HandleUdp: fatal error - A WCCP router does not support the forwarding method specified, only GRE supported");
1342 wccp2ConnectionClose();
1347 char *end
= ((char *) router_capability_header
) + sizeof(*router_capability_header
) + ntohs(router_capability_header
->capability_info_length
) - sizeof(struct wccp2_capability_info_header_t
);
1349 router_capability_element
= (struct wccp2_capability_element_t
*) (((char *) router_capability_header
) + sizeof(*router_capability_header
));
1351 while ((char *) router_capability_element
<= end
) {
1353 switch (ntohs(router_capability_element
->capability_type
)) {
1355 case WCCP2_CAPABILITY_FORWARDING_METHOD
:
1357 if (!(ntohl(router_capability_element
->capability_value
) & Config
.Wccp2
.forwarding_method
)) {
1358 debugs(80, DBG_IMPORTANT
, "wccp2HandleUdp: fatal error - A WCCP router has specified a different forwarding method " << ntohl(router_capability_element
->capability_value
) << ", expected " << Config
.Wccp2
.forwarding_method
);
1359 wccp2ConnectionClose();
1365 case WCCP2_CAPABILITY_ASSIGNMENT_METHOD
:
1367 if (!(ntohl(router_capability_element
->capability_value
) & Config
.Wccp2
.assignment_method
)) {
1368 debugs(80, DBG_IMPORTANT
, "wccp2HandleUdp: fatal error - A WCCP router has specified a different assignment method " << ntohl(router_capability_element
->capability_value
) << ", expected "<< Config
.Wccp2
.assignment_method
);
1369 wccp2ConnectionClose();
1375 case WCCP2_CAPABILITY_RETURN_METHOD
:
1377 if (!(ntohl(router_capability_element
->capability_value
) & Config
.Wccp2
.return_method
)) {
1378 debugs(80, DBG_IMPORTANT
, "wccp2HandleUdp: fatal error - A WCCP router has specified a different return method " << ntohl(router_capability_element
->capability_value
) << ", expected " << Config
.Wccp2
.return_method
);
1379 wccp2ConnectionClose();
1387 break; // ignore silently for now
1390 debugs(80, DBG_IMPORTANT
, "Unknown capability type in WCCPv2 Packet (" << ntohs(router_capability_element
->capability_type
) << ").");
1393 router_capability_element
= (struct wccp2_capability_element_t
*) (((char *) router_capability_element
) + sizeof(struct wccp2_item_header_t
) + ntohs(router_capability_element
->capability_length
));
1397 debugs(80, 5, "Cleaning out cache list");
1398 /* clean out the old cache list */
1400 for (cache_list_ptr
= &router_list_ptr
->cache_list_head
; cache_list_ptr
; cache_list_ptr
= cache_list_ptr_next
) {
1401 cache_list_ptr_next
= cache_list_ptr
->next
;
1403 if (cache_list_ptr
!= &router_list_ptr
->cache_list_head
) {
1404 xfree(cache_list_ptr
);
1408 router_list_ptr
->num_caches
= htonl(0);
1411 /* Check to see if we're the master cache and update the cache list */
1413 service_list_ptr
->lowest_ip
= 1;
1414 cache_list_ptr
= &router_list_ptr
->cache_list_head
;
1416 /* to find the list of caches, we start at the end of the router view header */
1418 ptr
= (char *) (router_view_header
) + sizeof(struct router_view_t
);
1420 /* Then we read the number of routers */
1421 memcpy(&tmp
, ptr
, sizeof(tmp
));
1423 /* skip the number plus all the ip's */
1425 ptr
+= sizeof(tmp
) + (ntohl(tmp
) * sizeof(struct in_addr
));
1427 /* Then read the number of caches */
1428 memcpy(&tmp
, ptr
, sizeof(tmp
));
1431 if (ntohl(tmp
) != 0) {
1432 /* search through the list of received-from ip addresses */
1434 for (num_caches
= 0; num_caches
< (int) ntohl(tmp
); ++num_caches
) {
1435 /* Get a copy of the ip */
1436 memset(&cache_address
, 0, sizeof(cache_address
)); // Make GCC happy
1438 switch (Config
.Wccp2
.assignment_method
) {
1440 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1442 cache_identity
= (struct wccp2_cache_identity_info_t
*) ptr
;
1444 ptr
+= sizeof(struct wccp2_cache_identity_info_t
);
1446 memcpy(&cache_address
, &cache_identity
->addr
, sizeof(struct in_addr
));
1448 cache_list_ptr
->weight
= ntohs(cache_identity
->weight
);
1451 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1453 cache_mask_info
= (struct cache_mask_info_t
*) ptr
;
1455 /* The mask assignment has an undocumented variable length entry here */
1457 if (ntohl(cache_mask_info
->num1
) == 3) {
1459 cache_mask_identity
= (struct wccp2_cache_mask_identity_info_t
*) ptr
;
1461 ptr
+= sizeof(struct wccp2_cache_mask_identity_info_t
);
1463 memcpy(&cache_address
, &cache_mask_identity
->addr
, sizeof(struct in_addr
));
1466 ptr
+= sizeof(struct cache_mask_info_t
);
1468 memcpy(&cache_address
, &cache_mask_info
->addr
, sizeof(struct in_addr
));
1471 cache_list_ptr
->weight
= 0;
1475 fatalf("Unknown Wccp2 assignment method\n");
1478 /* Update the cache list */
1479 cache_list_ptr
->cache_ip
= cache_address
;
1481 cache_list_ptr
->next
= (wccp2_cache_list_t
*) xcalloc(1, sizeof(struct wccp2_cache_list_t
));
1483 cache_list_ptr
= cache_list_ptr
->next
;
1485 cache_list_ptr
->next
= NULL
;
1487 debugs (80, 5, "checking cache list: (" << std::hex
<< cache_address
.s_addr
<< ":" << router_list_ptr
->local_ip
.s_addr
<< ")");
1489 /* Check to see if it's the master, or us */
1491 if (cache_address
.s_addr
== router_list_ptr
->local_ip
.s_addr
) {
1495 if (cache_address
.s_addr
< router_list_ptr
->local_ip
.s_addr
) {
1496 service_list_ptr
->lowest_ip
= 0;
1500 debugs(80, 5, "Adding ourselves as the only cache");
1502 /* Update the cache list */
1503 cache_list_ptr
->cache_ip
= router_list_ptr
->local_ip
;
1505 cache_list_ptr
->next
= (wccp2_cache_list_t
*) xcalloc(1, sizeof(struct wccp2_cache_list_t
));
1506 cache_list_ptr
= cache_list_ptr
->next
;
1507 cache_list_ptr
->next
= NULL
;
1509 service_list_ptr
->lowest_ip
= 1;
1514 wccp2SortCacheList(&router_list_ptr
->cache_list_head
);
1516 router_list_ptr
->num_caches
= htonl(num_caches
);
1518 if ((found
== 1) && (service_list_ptr
->lowest_ip
== 1)) {
1519 if (ntohl(router_view_header
->change_number
) != router_list_ptr
->member_change
) {
1520 debugs(80, 4, "Change detected - queueing up new assignment");
1521 router_list_ptr
->member_change
= ntohl(router_view_header
->change_number
);
1522 eventDelete(wccp2AssignBuckets
, NULL
);
1523 eventAdd("wccp2AssignBuckets", wccp2AssignBuckets
, NULL
, 15.0, 1);
1525 debugs(80, 5, "Change not detected (" << ntohl(router_view_header
->change_number
) << " = " << router_list_ptr
->member_change
<< ")");
1528 eventDelete(wccp2AssignBuckets
, NULL
);
1529 debugs(80, 5, "I am not the lowest ip cache - not assigning buckets");
1534 wccp2HereIam(void *voidnotused
)
1537 struct wccp2_service_list_t
*service_list_ptr
;
1539 struct wccp2_router_list_t
*router_list_ptr
;
1541 struct wccp2_identity_info_t
*wccp2_identity_info_ptr
;
1543 struct wccp2_mask_identity_info_t
*wccp2_mask_identity_info_ptr
;
1547 debugs(80, 6, "wccp2HereIam: Called");
1549 if (wccp2_connected
== 0) {
1550 debugs(80, DBG_IMPORTANT
, "wccp2HereIam: wccp2 socket closed. Shutting down WCCP2");
1554 /* Wait if store dirs are rebuilding */
1555 if (StoreController::store_dirs_rebuilding
&& Config
.Wccp2
.rebuildwait
) {
1556 eventAdd("wccp2HereIam", wccp2HereIam
, NULL
, 1.0, 1);
1560 router
.port(WCCP_PORT
);
1562 /* for each router on each service send a packet */
1563 service_list_ptr
= wccp2_service_list_head
;
1565 while (service_list_ptr
!= NULL
) {
1566 debugs(80, 5, "wccp2HereIam: sending to service id " << service_list_ptr
->info
.service_id
);
1568 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1569 router
= router_list_ptr
->router_sendto_address
;
1571 /* Set the cache id (ip) */
1573 switch (Config
.Wccp2
.assignment_method
) {
1575 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1577 wccp2_identity_info_ptr
= (struct wccp2_identity_info_t
*) service_list_ptr
->wccp2_identity_info_ptr
;
1578 wccp2_identity_info_ptr
->cache_identity
.addr
= router_list_ptr
->local_ip
;
1581 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1583 wccp2_mask_identity_info_ptr
= (struct wccp2_mask_identity_info_t
*) service_list_ptr
->wccp2_identity_info_ptr
;
1584 wccp2_mask_identity_info_ptr
->cache_identity
.addr
= router_list_ptr
->local_ip
;
1588 fatalf("Unknown Wccp2 assignment method\n");
1591 /* Security update, if needed */
1593 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
1594 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
);
1597 debugs(80, 3, "Sending HereIam packet size " << service_list_ptr
->wccp_packet_size
);
1598 /* Send the packet */
1600 if (wccp2_numrouters
> 1) {
1601 comm_udp_sendto(theWccp2Connection
,
1603 &service_list_ptr
->wccp_packet
,
1604 service_list_ptr
->wccp_packet_size
);
1607 if (send(theWccp2Connection
, &service_list_ptr
->wccp_packet
, service_list_ptr
->wccp_packet_size
, 0) < static_cast<int>(service_list_ptr
->wccp_packet_size
))
1608 debugs(80, 2, "ERROR: failed to send WCCPv2 HERE_I_AM packet to " << router
<< " : " << xstrerror());
1612 service_list_ptr
= service_list_ptr
->next
;
1615 eventAdd("wccp2HereIam", wccp2HereIam
, NULL
, 10.0, 1);
1619 wccp2AssignBuckets(void *voidnotused
)
1622 struct wccp2_service_list_t
*service_list_ptr
;
1624 struct wccp2_router_list_t
*router_list_ptr
;
1626 struct wccp2_cache_list_t
*cache_list_ptr
;
1627 char wccp_packet
[WCCP_RESPONSE_SIZE
];
1628 short int offset
, saved_offset
, assignment_offset
, alt_assignment_offset
;
1630 struct sockaddr_in router
;
1633 uint32_t service_flags
;
1634 unsigned short port
= WCCP_PORT
;
1636 /* Packet segments */
1638 struct wccp2_message_header_t
*main_header
;
1640 struct wccp2_security_md5_t
*security
= NULL
;
1641 /* service from service struct */
1643 struct wccp2_item_header_t
*assignment_header
;
1645 struct wccp2_item_header_t
*alt_assignment_type_header
= NULL
;
1647 struct assignment_key_t
*assignment_key
;
1648 /* number of routers */
1650 struct wccp2_router_assign_element_t
*router_assign
;
1651 /* number of caches */
1653 struct in_addr
*cache_address
;
1654 /* Alternative assignement mask/values */
1657 struct wccp2_mask_element_t
*mask_element
;
1659 struct wccp2_value_element_t
*value_element
;
1660 int valuecounter
, value
;
1663 assignment_offset
= alt_assignment_offset
= 0;
1665 router_len
= sizeof(router
);
1666 memset(&router
, '\0', router_len
);
1667 router
.sin_family
= AF_INET
;
1668 router
.sin_port
= htons(port
);
1670 /* Start main header - fill in length later */
1673 main_header
= (struct wccp2_message_header_t
*) &wccp_packet
[offset
];
1674 main_header
->type
= htonl(WCCP2_REDIRECT_ASSIGN
);
1675 main_header
->version
= htons(WCCP2_VERSION
);
1677 debugs(80, 2, "Running wccp2AssignBuckets");
1678 service_list_ptr
= wccp2_service_list_head
;
1680 while (service_list_ptr
!= NULL
) {
1681 /* If we're not the lowest, we don't need to worry */
1683 if (service_list_ptr
->lowest_ip
== 0) {
1685 service_list_ptr
= service_list_ptr
->next
;
1689 /* reset the offset */
1691 offset
= sizeof(struct wccp2_message_header_t
);
1693 /* build packet header from hereIam packet */
1695 /* XXX this should be made more generic! */
1696 /* XXX and I hate magic numbers! */
1697 switch (service_list_ptr
->wccp2_security_type
) {
1699 case WCCP2_NO_SECURITY
:
1701 security
= (struct wccp2_security_md5_t
*) &wccp_packet
[offset
];
1702 memcpy(security
, service_list_ptr
->security_info
, 8);
1706 case WCCP2_MD5_SECURITY
:
1708 security
= (struct wccp2_security_md5_t
*) &wccp_packet
[offset
];
1710 memcpy(security
, service_list_ptr
->security_info
, sizeof(struct wccp2_security_md5_t
));
1712 offset
+= sizeof(struct wccp2_security_md5_t
);
1716 fatalf("Unknown Wccp2 security type\n");
1721 memcpy(&wccp_packet
[offset
], service_list_ptr
->service_info
, sizeof(struct wccp2_service_info_t
));
1723 offset
+= sizeof(struct wccp2_service_info_t
);
1725 /* assignment header - fill in length later */
1727 assignment_header
= (struct wccp2_item_header_t
*) &wccp_packet
[offset
];
1729 switch (Config
.Wccp2
.assignment_method
) {
1731 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1732 assignment_header
->type
= htons(WCCP2_REDIRECT_ASSIGNMENT
);
1734 offset
+= sizeof(struct wccp2_item_header_t
);
1735 assignment_offset
= offset
;
1738 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1739 assignment_header
->type
= htons(WCCP2_ALT_ASSIGNMENT
);
1741 offset
+= sizeof(struct wccp2_item_header_t
);
1742 assignment_offset
= offset
;
1744 /* The alternative assignment has an extra header, fill in length later */
1746 alt_assignment_type_header
= (struct wccp2_item_header_t
*) &wccp_packet
[offset
];
1747 alt_assignment_type_header
->type
= htons(WCCP2_MASK_ASSIGNMENT
);
1749 offset
+= sizeof(struct wccp2_item_header_t
);
1750 alt_assignment_offset
= offset
;
1755 fatalf("Unknown Wccp2 assignment method\n");
1758 /* Assignment key - fill in master ip later */
1760 assignment_key
= (struct assignment_key_t
*) &wccp_packet
[offset
];
1762 assignment_key
->master_number
= htonl(++service_list_ptr
->change_num
);
1764 offset
+= sizeof(struct assignment_key_t
);
1766 /* Number of routers */
1767 memcpy(&wccp_packet
[offset
], &service_list_ptr
->num_routers
, sizeof(service_list_ptr
->num_routers
));
1769 offset
+= sizeof(service_list_ptr
->num_routers
);
1771 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1775 router_assign
= (struct wccp2_router_assign_element_t
*) &wccp_packet
[offset
];
1776 router_assign
->router_address
= router_list_ptr
->info
->router_address
;
1777 router_assign
->received_id
= router_list_ptr
->info
->received_id
;
1778 router_assign
->change_number
= htonl(router_list_ptr
->member_change
);
1780 offset
+= sizeof(struct wccp2_router_assign_element_t
);
1783 saved_offset
= offset
;
1785 for (router_list_ptr
= &service_list_ptr
->router_list_head
; router_list_ptr
->next
!= NULL
; router_list_ptr
= router_list_ptr
->next
) {
1786 unsigned long *weight
= (unsigned long *)xcalloc(sizeof(*weight
), ntohl(router_list_ptr
->num_caches
));
1787 unsigned long total_weight
= 0;
1788 int num_caches
= ntohl(router_list_ptr
->num_caches
);
1790 offset
= saved_offset
;
1792 switch (Config
.Wccp2
.assignment_method
) {
1794 case WCCP2_ASSIGNMENT_METHOD_HASH
:
1795 /* Number of caches */
1796 memcpy(&wccp_packet
[offset
], &router_list_ptr
->num_caches
, sizeof(router_list_ptr
->num_caches
));
1797 offset
+= sizeof(router_list_ptr
->num_caches
);
1802 for (cache
= 0, cache_list_ptr
= &router_list_ptr
->cache_list_head
; cache_list_ptr
->next
; cache_list_ptr
= cache_list_ptr
->next
, ++cache
) {
1805 cache_address
= (struct in_addr
*) &wccp_packet
[offset
];
1807 memcpy(cache_address
, &cache_list_ptr
->cache_ip
, sizeof(struct in_addr
));
1808 total_weight
+= cache_list_ptr
->weight
<< 12;
1809 weight
[cache
] = cache_list_ptr
->weight
<< 12;
1811 offset
+= sizeof(struct in_addr
);
1816 buckets
= (char *) &wccp_packet
[offset
];
1818 memset(buckets
, '\0', WCCP_BUCKETS
);
1820 if (num_caches
!= 0) {
1821 if (total_weight
== 0) {
1822 for (bucket_counter
= 0; bucket_counter
< WCCP_BUCKETS
; ++bucket_counter
) {
1823 buckets
[bucket_counter
] = (char) (bucket_counter
% num_caches
);
1826 unsigned long *assigned
= (unsigned long *)xcalloc(sizeof(*assigned
), num_caches
);
1827 unsigned long done
= 0;
1829 unsigned long per_bucket
= total_weight
/ WCCP_BUCKETS
;
1831 for (bucket_counter
= 0; bucket_counter
< WCCP_BUCKETS
; ++bucket_counter
) {
1835 for (n
= num_caches
; n
; --n
) {
1838 if (cache
>= num_caches
)
1841 if (!weight
[cache
]) {
1846 if (assigned
[cache
] <= done
)
1850 buckets
[bucket_counter
] = (char) cache
;
1851 step
= per_bucket
* total_weight
/ weight
[cache
];
1852 assigned
[cache
] += step
;
1856 safe_free(assigned
);
1860 offset
+= (WCCP_BUCKETS
* sizeof(char));
1864 case WCCP2_ASSIGNMENT_METHOD_MASK
:
1865 num_maskval
= htonl(1);
1866 memcpy(&wccp_packet
[offset
], &num_maskval
, sizeof(int));
1867 offset
+= sizeof(int);
1869 mask_element
= (struct wccp2_mask_element_t
*) &wccp_packet
[offset
];
1870 service_flags
= ntohl(service_list_ptr
->service_info
->service_flags
);
1872 if ((service_flags
& WCCP2_SERVICE_SRC_IP_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
)) {
1873 mask_element
->source_ip_mask
= htonl(0x00001741);
1874 mask_element
->dest_ip_mask
= 0;
1875 mask_element
->source_port_mask
= 0;
1876 mask_element
->dest_port_mask
= 0;
1877 } 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
)) {
1878 mask_element
->source_ip_mask
= 0;
1879 mask_element
->dest_ip_mask
= htonl(0x00001741);
1880 mask_element
->source_port_mask
= 0;
1881 mask_element
->dest_port_mask
= 0;
1882 } else if ((service_flags
& WCCP2_SERVICE_SRC_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
)) {
1883 mask_element
->source_ip_mask
= 0;
1884 mask_element
->dest_ip_mask
= 0;
1885 mask_element
->source_port_mask
= htons(0x1741);
1886 mask_element
->dest_port_mask
= 0;
1887 } else if ((service_flags
& WCCP2_SERVICE_DST_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
)) {
1888 mask_element
->source_ip_mask
= 0;
1889 mask_element
->dest_ip_mask
= 0;
1890 mask_element
->source_port_mask
= 0;
1891 mask_element
->dest_port_mask
= htons(0x1741);
1893 fatalf("Unknown service hash method\n");
1896 mask_element
->number_values
= htonl(64);
1898 offset
+= sizeof(struct wccp2_mask_element_t
);
1900 cache_list_ptr
= &router_list_ptr
->cache_list_head
;
1903 for (valuecounter
= 0; valuecounter
< 64; ++valuecounter
) {
1905 value_element
= (struct wccp2_value_element_t
*) &wccp_packet
[offset
];
1907 /* Update the value according the the "correct" formula */
1909 for (; (value
& 0x1741) != value
; ++value
) {
1910 assert(value
<= 0x1741);
1913 if ((service_flags
& WCCP2_SERVICE_SRC_IP_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
)) {
1914 value_element
->source_ip_value
= htonl(value
);
1915 value_element
->dest_ip_value
= 0;
1916 value_element
->source_port_value
= 0;
1917 value_element
->dest_port_value
= 0;
1918 } 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
)) {
1919 value_element
->source_ip_value
= 0;
1920 value_element
->dest_ip_value
= htonl(value
);
1921 value_element
->source_port_value
= 0;
1922 value_element
->dest_port_value
= 0;
1923 } else if ((service_flags
& WCCP2_SERVICE_SRC_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
)) {
1924 value_element
->source_ip_value
= 0;
1925 value_element
->dest_ip_value
= 0;
1926 value_element
->source_port_value
= htons(value
);
1927 value_element
->dest_port_value
= 0;
1928 } else if ((service_flags
& WCCP2_SERVICE_DST_PORT_HASH
) || (service_flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
)) {
1929 value_element
->source_ip_value
= 0;
1930 value_element
->dest_ip_value
= 0;
1931 value_element
->source_port_value
= 0;
1932 value_element
->dest_port_value
= htons(value
);
1934 fatalf("Unknown service hash method\n");
1937 value_element
->cache_ip
= cache_list_ptr
->cache_ip
;
1939 offset
+= sizeof(struct wccp2_value_element_t
);
1942 /* Assign the next value to the next cache */
1944 if ((cache_list_ptr
->next
) && (cache_list_ptr
->next
->next
))
1945 cache_list_ptr
= cache_list_ptr
->next
;
1947 cache_list_ptr
= &router_list_ptr
->cache_list_head
;
1950 /* Fill in length */
1951 alt_assignment_type_header
->length
= htons(offset
- alt_assignment_offset
);
1956 fatalf("Unknown Wccp2 assignment method\n");
1959 /* Fill in length */
1961 assignment_header
->length
= htons(offset
- assignment_offset
);
1963 /* Fill in assignment key */
1964 assignment_key
->master_ip
= router_list_ptr
->local_ip
;
1968 main_header
->length
= htons(offset
- sizeof(struct wccp2_message_header_t
));
1970 /* set the destination address */
1971 router
.sin_addr
= router_list_ptr
->router_sendto_address
;
1973 /* Security update, if needed */
1975 if (service_list_ptr
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
1976 wccp2_update_md5_security(service_list_ptr
->wccp_password
, (char *) security
, wccp_packet
, offset
);
1979 if (ntohl(router_list_ptr
->num_caches
)) {
1982 /* FIXME INET6 : drop temp conversion */
1983 Ip::Address
tmp_rtr(router
);
1985 if (wccp2_numrouters
> 1) {
1986 comm_udp_sendto(theWccp2Connection
,
1992 if (send(theWccp2Connection
, &wccp_packet
, offset
, 0) < static_cast<int>(offset
))
1993 debugs(80, 2, "ERROR: failed to send WCCPv2 HERE_I_AM packet to " << tmp_rtr
<< " : " << xstrerror());
1999 service_list_ptr
= service_list_ptr
->next
;
2004 * Configuration option parsing code
2008 * Parse wccp2_return_method and wccp2_forwarding_method options
2009 * they can be '1' aka 'gre' or '2' aka 'l2'
2010 * repesenting the integer numeric of the same.
2013 parse_wccp2_method(int *method
)
2017 /* Snarf the method */
2018 if ((t
= ConfigParser::NextToken()) == NULL
) {
2019 debugs(80, DBG_CRITICAL
, "wccp2_*_method: missing setting.");
2023 /* update configuration if its valid */
2024 if (strcmp(t
, "gre") == 0 || strcmp(t
, "1") == 0) {
2025 *method
= WCCP2_METHOD_GRE
;
2026 } else if (strcmp(t
, "l2") == 0 || strcmp(t
, "2") == 0) {
2027 *method
= WCCP2_METHOD_L2
;
2029 debugs(80, DBG_CRITICAL
, "wccp2_*_method: unknown setting, got " << t
);
2035 dump_wccp2_method(StoreEntry
* e
, const char *label
, int v
)
2038 case WCCP2_METHOD_GRE
:
2039 storeAppendPrintf(e
, "%s gre\n", label
);
2041 case WCCP2_METHOD_L2
:
2042 storeAppendPrintf(e
, "%s l2\n", label
);
2045 debugs(80, DBG_CRITICAL
, "FATAL: WCCPv2 configured method (" << v
<< ") is not valid.");
2051 free_wccp2_method(int *v
)
2055 * Parse wccp2_assignment_method option
2056 * they can be '1' aka 'hash' or '2' aka 'mask'
2057 * repesenting the integer numeric of the same.
2060 parse_wccp2_amethod(int *method
)
2064 /* Snarf the method */
2065 if ((t
= ConfigParser::NextToken()) == NULL
) {
2066 debugs(80, DBG_CRITICAL
, "wccp2_assignment_method: missing setting.");
2070 /* update configuration if its valid */
2071 if (strcmp(t
, "hash") == 0 || strcmp(t
, "1") == 0) {
2072 *method
= WCCP2_ASSIGNMENT_METHOD_HASH
;
2073 } else if (strcmp(t
, "mask") == 0 || strcmp(t
, "2") == 0) {
2074 *method
= WCCP2_ASSIGNMENT_METHOD_MASK
;
2076 debugs(80, DBG_CRITICAL
, "wccp2_assignment_method: unknown setting, got " << t
);
2082 dump_wccp2_amethod(StoreEntry
* e
, const char *label
, int v
)
2085 case WCCP2_ASSIGNMENT_METHOD_HASH
:
2086 storeAppendPrintf(e
, "%s hash\n", label
);
2088 case WCCP2_ASSIGNMENT_METHOD_MASK
:
2089 storeAppendPrintf(e
, "%s mask\n", label
);
2092 debugs(80, DBG_CRITICAL
, "FATAL: WCCPv2 configured " << label
<< " (" << v
<< ") is not valid.");
2098 free_wccp2_amethod(int *v
)
2104 * wccp2_service {standard|dynamic} {id} (password=password)
2107 parse_wccp2_service(void *v
)
2112 int security_type
= WCCP2_NO_SECURITY
;
2113 char wccp_password
[WCCP2_PASSWORD_LEN
+ 1];
2115 if (wccp2_connected
== 1) {
2116 debugs(80, DBG_IMPORTANT
, "WCCPv2: Somehow reparsing the configuration without having shut down WCCP! Try reloading squid again.");
2120 /* Snarf the type */
2121 if ((t
= ConfigParser::NextToken()) == NULL
) {
2122 debugs(80, DBG_CRITICAL
, "wccp2ParseServiceInfo: missing service info type (standard|dynamic)");
2126 if (strcmp(t
, "standard") == 0) {
2127 service
= WCCP2_SERVICE_STANDARD
;
2128 } else if (strcmp(t
, "dynamic") == 0) {
2129 service
= WCCP2_SERVICE_DYNAMIC
;
2131 debugs(80, DBG_CRITICAL
, "wccp2ParseServiceInfo: bad service info type (expected standard|dynamic, got " << t
<< ")");
2136 service_id
= GetInteger();
2138 if (service_id
< 0 || service_id
> 255) {
2139 debugs(80, DBG_CRITICAL
, "ERROR: invalid WCCP service id " << service_id
<< " (must be between 0 .. 255)");
2143 memset(wccp_password
, 0, sizeof(wccp_password
));
2144 /* Handle password, if any */
2146 if ((t
= ConfigParser::NextToken()) != NULL
) {
2147 if (strncmp(t
, "password=", 9) == 0) {
2148 security_type
= WCCP2_MD5_SECURITY
;
2149 strncpy(wccp_password
, t
+ 9, WCCP2_PASSWORD_LEN
);
2153 /* Create a placeholder service record */
2154 wccp2_add_service_list(service
, service_id
, 0, 0, 0, empty_portlist
, security_type
, wccp_password
);
2158 dump_wccp2_service(StoreEntry
* e
, const char *label
, void *v
)
2161 struct wccp2_service_list_t
*srv
;
2162 srv
= wccp2_service_list_head
;
2164 while (srv
!= NULL
) {
2165 debugs(80, 3, "dump_wccp2_service: id " << srv
->info
.service_id
<< ", type " << srv
->info
.service
);
2166 storeAppendPrintf(e
, "%s %s %d", label
,
2167 (srv
->info
.service
== WCCP2_SERVICE_DYNAMIC
) ? "dynamic" : "standard",
2168 srv
->info
.service_id
);
2170 if (srv
->wccp2_security_type
== WCCP2_MD5_SECURITY
) {
2171 storeAppendPrintf(e
, " %s", srv
->wccp_password
);
2174 storeAppendPrintf(e
, "\n");
2181 free_wccp2_service(void *v
)
2185 check_null_wccp2_service(void *v
)
2187 return !wccp2_service_list_head
;
2193 * wccp2_service_info {id} stuff..
2197 * + flags=flag,flag,flag..
2198 * + proto=protocol (tcp|udp)
2199 * + ports=port,port,port (up to a max of 8)
2200 * + priority=priority (0->255)
2202 * The flags here are:
2203 * src_ip_hash, dst_ip_hash, source_port_hash, dst_port_hash, ports_defined,
2204 * ports_source, src_ip_alt_hash, dst_ip_alt_hash, src_port_alt_hash, dst_port_alt_hash
2207 parse_wccp2_service_flags(char *flags
)
2215 while (size_t len
= strcspn(flag
, ",")) {
2217 if (strncmp(flag
, "src_ip_hash", len
) == 0) {
2218 retflag
|= WCCP2_SERVICE_SRC_IP_HASH
;
2219 } else if (strncmp(flag
, "dst_ip_hash", len
) == 0) {
2220 retflag
|= WCCP2_SERVICE_DST_IP_HASH
;
2221 } else if (strncmp(flag
, "source_port_hash", len
) == 0) {
2222 retflag
|= WCCP2_SERVICE_SRC_PORT_HASH
;
2223 } else if (strncmp(flag
, "dst_port_hash", len
) == 0) {
2224 retflag
|= WCCP2_SERVICE_DST_PORT_HASH
;
2225 } else if (strncmp(flag
, "ports_source", len
) == 0) {
2226 retflag
|= WCCP2_SERVICE_PORTS_SOURCE
;
2227 } else if (strncmp(flag
, "src_ip_alt_hash", len
) == 0) {
2228 retflag
|= WCCP2_SERVICE_SRC_IP_ALT_HASH
;
2229 } else if (strncmp(flag
, "dst_ip_alt_hash", len
) == 0) {
2230 retflag
|= WCCP2_SERVICE_DST_IP_ALT_HASH
;
2231 } else if (strncmp(flag
, "src_port_alt_hash", len
) == 0) {
2232 retflag
|= WCCP2_SERVICE_SRC_PORT_ALT_HASH
;
2233 } else if (strncmp(flag
, "dst_port_alt_hash", len
) == 0) {
2234 retflag
|= WCCP2_SERVICE_DST_PORT_ALT_HASH
;
2237 fatalf("Unknown wccp2 service flag: %s\n", flag
);
2240 if (flag
[len
] == '\0')
2250 parse_wccp2_service_ports(char *options
, int portlist
[])
2257 char *tmp
= options
;
2259 while (size_t len
= strcspn(tmp
, ",")) {
2260 if (i
>= WCCP2_NUMPORTS
) {
2261 fatalf("parse_wccp2_service_ports: too many ports (maximum: 8) in list '%s'\n", options
);
2265 if (p
< 1 || p
> 65535) {
2266 fatalf("parse_wccp2_service_ports: port value '%s' isn't valid (1..65535)\n", tmp
);
2271 if (tmp
[len
] == '\0')
2278 parse_wccp2_service_info(void *v
)
2283 int portlist
[WCCP2_NUMPORTS
];
2284 int protocol
= -1; /* IPPROTO_TCP | IPPROTO_UDP */
2286 struct wccp2_service_list_t
*srv
;
2289 if (wccp2_connected
== 1) {
2290 debugs(80, DBG_IMPORTANT
, "WCCPv2: Somehow reparsing the configuration without having shut down WCCP! Try reloading squid again.");
2294 debugs(80, 5, "parse_wccp2_service_info: called");
2295 memset(portlist
, 0, sizeof(portlist
));
2296 /* First argument: id */
2297 service_id
= GetInteger();
2299 if (service_id
< 0 || service_id
> 255) {
2300 debugs(80, DBG_CRITICAL
, "ERROR: invalid WCCP service id " << service_id
<< " (must be between 0 .. 255)");
2304 /* Next: find the (hopefully!) existing service */
2305 srv
= wccp2_get_service_by_id(WCCP2_SERVICE_DYNAMIC
, service_id
);
2308 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
);
2311 /* Next: loop until we don't have any more tokens */
2312 while ((t
= ConfigParser::NextToken()) != NULL
) {
2313 if (strncmp(t
, "flags=", 6) == 0) {
2314 /* XXX eww, string pointer math */
2315 flags
= parse_wccp2_service_flags(t
+ 6);
2316 } else if (strncmp(t
, "ports=", 6) == 0) {
2317 parse_wccp2_service_ports(t
+ 6, portlist
);
2318 flags
|= WCCP2_SERVICE_PORTS_DEFINED
;
2319 } else if (strncmp(t
, "protocol=tcp", 12) == 0) {
2320 protocol
= IPPROTO_TCP
;
2321 } else if (strncmp(t
, "protocol=udp", 12) == 0) {
2322 protocol
= IPPROTO_UDP
;
2323 } else if (strncmp(t
, "protocol=", 9) == 0) {
2324 fatalf("parse_wccp2_service_info: id %d: unknown protocol (%s) - must be tcp or udp!\n", service_id
, t
);
2325 } else if (strncmp(t
, "priority=", 9) == 0) {
2326 priority
= strtol(t
+ 9, &end
, 0);
2328 if (priority
< 0 || priority
> 255) {
2329 fatalf("parse_wccp2_service_info: id %d: %s out of range (0..255)!\n", service_id
, t
);
2332 fatalf("parse_wccp2_service_info: id %d: unknown option '%s'\n", service_id
, t
);
2336 /* Check everything is set */
2337 if (priority
== -1) {
2338 fatalf("parse_wccp2_service_info: service %d: no priority defined (valid: 0..255)!\n", service_id
);
2341 if (protocol
== -1) {
2342 fatalf("parse_wccp2_service_info: service %d: no protocol defined (valid: tcp or udp)!\n", service_id
);
2345 if (!(flags
& WCCP2_SERVICE_PORTS_DEFINED
)) {
2346 fatalf("parse_wccp2_service_info: service %d: no ports defined!\n", service_id
);
2349 /* rightio! now we can update */
2350 wccp2_update_service(srv
, WCCP2_SERVICE_DYNAMIC
, service_id
, priority
,
2351 protocol
, flags
, portlist
);
2357 dump_wccp2_service_info(StoreEntry
* e
, const char *label
, void *v
)
2361 struct wccp2_service_list_t
*srv
;
2363 srv
= wccp2_service_list_head
;
2365 while (srv
!= NULL
) {
2366 debugs(80, 3, "dump_wccp2_service_info: id " << srv
->info
.service_id
<< " (type " << srv
->info
.service
<< ")");
2368 /* We don't need to spit out information for standard services */
2370 if (srv
->info
.service
== WCCP2_SERVICE_STANDARD
) {
2371 debugs(80, 3, "dump_wccp2_service_info: id " << srv
->info
.service_id
<< ": standard service, not dumping info");
2378 storeAppendPrintf(e
, "%s %d", label
, srv
->info
.service_id
);
2381 storeAppendPrintf(e
, " priority=%d", srv
->info
.service_priority
);
2384 flags
= ntohl(srv
->info
.service_flags
);
2388 storeAppendPrintf(e
, " flags=");
2390 if (flags
& WCCP2_SERVICE_SRC_IP_HASH
) {
2391 storeAppendPrintf(e
, "%ssrc_ip_hash", comma
? "," : "");
2395 if (flags
& WCCP2_SERVICE_DST_IP_HASH
) {
2396 storeAppendPrintf(e
, "%sdst_ip_hash", comma
? "," : "");
2400 if (flags
& WCCP2_SERVICE_SRC_PORT_HASH
) {
2401 storeAppendPrintf(e
, "%ssource_port_hash", comma
? "," : "");
2405 if (flags
& WCCP2_SERVICE_DST_PORT_HASH
) {
2406 storeAppendPrintf(e
, "%sdst_port_hash", comma
? "," : "");
2410 if (flags
& WCCP2_SERVICE_PORTS_DEFINED
) {
2411 storeAppendPrintf(e
, "%sports_defined", comma
? "," : "");
2415 if (flags
& WCCP2_SERVICE_PORTS_SOURCE
) {
2416 storeAppendPrintf(e
, "%sports_source", comma
? "," : "");
2420 if (flags
& WCCP2_SERVICE_SRC_IP_ALT_HASH
) {
2421 storeAppendPrintf(e
, "%ssrc_ip_alt_hash", comma
? "," : "");
2425 if (flags
& WCCP2_SERVICE_DST_IP_ALT_HASH
) {
2426 storeAppendPrintf(e
, "%ssrc_ip_alt_hash", comma
? "," : "");
2430 if (flags
& WCCP2_SERVICE_SRC_PORT_ALT_HASH
) {
2431 storeAppendPrintf(e
, "%ssrc_port_alt_hash", comma
? "," : "");
2435 if (flags
& WCCP2_SERVICE_DST_PORT_ALT_HASH
) {
2436 storeAppendPrintf(e
, "%sdst_port_alt_hash", comma
? "," : "");
2444 if (srv
->info
.port0
!= 0) {
2445 storeAppendPrintf(e
, "%s%d", comma
? "," : " ports=", ntohs(srv
->info
.port0
));
2449 if (srv
->info
.port1
!= 0) {
2450 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port1
));
2454 if (srv
->info
.port2
!= 0) {
2455 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port2
));
2459 if (srv
->info
.port3
!= 0) {
2460 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port3
));
2464 if (srv
->info
.port4
!= 0) {
2465 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port4
));
2469 if (srv
->info
.port5
!= 0) {
2470 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port5
));
2474 if (srv
->info
.port6
!= 0) {
2475 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port6
));
2479 if (srv
->info
.port7
!= 0) {
2480 storeAppendPrintf(e
, "%s%d", comma
? "," : "ports=", ntohs(srv
->info
.port7
));
2485 storeAppendPrintf(e
, " protocol=%s", (srv
->info
.service_protocol
== IPPROTO_TCP
) ? "tcp" : "udp");
2487 storeAppendPrintf(e
, "\n");
2493 /* Sort the cache list by doing a "selection sort" by IP address */
2495 wccp2SortCacheList(struct wccp2_cache_list_t
*head
)
2497 struct wccp2_cache_list_t tmp
;
2498 struct wccp2_cache_list_t
*this_item
;
2499 struct wccp2_cache_list_t
*find_item
;
2500 struct wccp2_cache_list_t
*next_lowest
;
2502 /* Go through each position in the list one at a time */
2503 for (this_item
= head
; this_item
->next
; this_item
= this_item
->next
) {
2504 /* Find the item with the lowest IP */
2505 next_lowest
= this_item
;
2507 for (find_item
= this_item
; find_item
->next
; find_item
= find_item
->next
) {
2508 if (find_item
->cache_ip
.s_addr
< next_lowest
->cache_ip
.s_addr
) {
2509 next_lowest
= find_item
;
2512 /* Swap if we need to */
2513 if (next_lowest
!= this_item
) {
2514 /* First make a copy of the current item */
2515 memcpy(&tmp
, this_item
, sizeof(struct wccp2_cache_list_t
));
2517 /* Next update the pointers to maintain the linked list */
2518 tmp
.next
= next_lowest
->next
;
2519 next_lowest
->next
= this_item
->next
;
2521 /* Finally copy the updated items to their correct location */
2522 memcpy(this_item
, next_lowest
, sizeof(struct wccp2_cache_list_t
));
2523 memcpy(next_lowest
, &tmp
, sizeof(struct wccp2_cache_list_t
));
2529 free_wccp2_service_info(void *v
)
2532 #endif /* USE_WCCPv2 */