]> git.ipfire.org Git - thirdparty/squid.git/blame - src/wccp2.cc
Bootstrapped
[thirdparty/squid.git] / src / wccp2.cc
CommitLineData
0b0cfcf2 1
2/*
25e26086 3 * $Id: wccp2.cc,v 1.13 2006/12/24 15:24:12 serassio Exp $
0b0cfcf2 4 *
5 * DEBUG: section 80 WCCP Support
47c151e0 6 * AUTHOR: Steven Wilton
0b0cfcf2 7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
19 *
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.
24 *
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.
29 *
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.
33 *
34 */
35#include "squid.h"
36#include "comm.h"
a553a5a3 37#include "event.h"
0b0cfcf2 38#include "Parsing.h"
a553a5a3 39#include "Store.h"
bef81ea5 40#include "SwapDir.h"
0b0cfcf2 41
42#if USE_WCCPv2
43#include <netdb.h>
44
45#define WCCP_PORT 2048
0b0cfcf2 46#define WCCP_RESPONSE_SIZE 12448
0b0cfcf2 47#define WCCP_BUCKETS 256
48
0b0cfcf2 49static int theWccp2Connection = -1;
50static int wccp2_connected = 0;
51
52static PF wccp2HandleUdp;
53static EVH wccp2HereIam;
54static EVH wccp2AssignBuckets;
55
56/* KDW WCCP V2 */
57#define WCCP2_HERE_I_AM 10
58#define WCCP2_I_SEE_YOU 11
59#define WCCP2_REDIRECT_ASSIGN 12
60#define WCCP2_REMOVAL_QUERY 13
c1f55201 61
0b0cfcf2 62#define WCCP2_VERSION 0x200
63
64#define WCCP2_SECURITY_INFO 0
65#define WCCP2_NO_SECURITY 0
66#define WCCP2_MD5_SECURITY 1
67
68#define WCCP2_SERVICE_INFO 1
69#define WCCP2_SERVICE_STANDARD 0
70#define WCCP2_SERVICE_DYNAMIC 1
71#define WCCP2_SERVICE_ID_HTTP 0x00
72
73#define WCCP2_SERVICE_SRC_IP_HASH 0x1
74#define WCCP2_SERVICE_DST_IP_HASH 0x2
b7d249f9 75#define WCCP2_SERVICE_SRC_PORT_HASH 0x4
0b0cfcf2 76#define WCCP2_SERVICE_DST_PORT_HASH 0x8
77#define WCCP2_SERVICE_PORTS_DEFINED 0x10
78#define WCCP2_SERVICE_PORTS_SOURCE 0x20
79#define WCCP2_SERVICE_SRC_IP_ALT_HASH 0x100
80#define WCCP2_SERVICE_DST_IP_ALT_HASH 0x200
81#define WCCP2_SERVICE_SRC_PORT_ALT_HASH 0x400
82#define WCCP2_SERVICE_DST_PORT_ALT_HASH 0x800
83
84#define WCCP2_ROUTER_ID_INFO 2
85
86#define WCCP2_WC_ID_INFO 3
87
88#define WCCP2_RTR_VIEW_INFO 4
89
90#define WCCP2_WC_VIEW_INFO 5
91
92#define WCCP2_REDIRECT_ASSIGNMENT 6
93
94#define WCCP2_QUERY_INFO 7
95
96#define WCCP2_CAPABILITY_INFO 8
97
b7d249f9 98#define WCCP2_ALT_ASSIGNMENT 13
99
100#define WCCP2_ASSIGN_MAP 14
101
102#define WCCP2_COMMAND_EXTENSION 15
103
0b0cfcf2 104#define WCCP2_CAPABILITY_FORWARDING_METHOD 0x01
105#define WCCP2_CAPABILITY_ASSIGNMENT_METHOD 0x02
106#define WCCP2_CAPABILITY_RETURN_METHOD 0x03
107
c1f55201 108#define WCCP2_FORWARDING_METHOD_GRE 0x00000001
109#define WCCP2_FORWARDING_METHOD_L2 0x00000002
110
111#define WCCP2_ASSIGNMENT_METHOD_HASH 0x00000001
112#define WCCP2_ASSIGNMENT_METHOD_MASK 0x00000002
113
114#define WCCP2_PACKET_RETURN_METHOD_GRE 0x00000001
115#define WCCP2_PACKET_RETURN_METHOD_L2 0x00000002
0b0cfcf2 116
b7d249f9 117#define WCCP2_HASH_ASSIGNMENT 0x00
118#define WCCP2_MASK_ASSIGNMENT 0x01
119
0b0cfcf2 120#define WCCP2_NONE_SECURITY_LEN 0
121#define WCCP2_MD5_SECURITY_LEN 16
122
123/* Useful defines */
124#define WCCP2_NUMPORTS 8
125#define WCCP2_PASSWORD_LEN 8
126
127/* WCCP v2 packet header */
128
129struct wccp2_here_i_am_header_t
130{
131 uint32_t type;
132 uint16_t version;
133 uint16_t length;
134};
135
136static struct wccp2_here_i_am_header_t wccp2_here_i_am_header;
137
138/* Security struct for the "no security" option */
139
140struct wccp2_security_none_t
141{
142 uint16_t security_type;
143 uint16_t security_length;
144 uint32_t security_option;
145};
146
147struct wccp2_security_md5_t
148{
149 uint16_t security_type;
150 uint16_t security_length;
151 uint32_t security_option;
152 uint8_t security_implementation[WCCP2_MD5_SECURITY_LEN];
153};
154
155/* Service info struct */
156
157struct wccp2_service_info_t
158{
159 uint16_t service_type;
160 uint16_t service_length;
161 uint8_t service;
162 uint8_t service_id;
163 uint8_t service_priority;
164 uint8_t service_protocol;
165 uint32_t service_flags;
166 uint16_t port0;
167 uint16_t port1;
168 uint16_t port2;
169 uint16_t port3;
170 uint16_t port4;
171 uint16_t port5;
172 uint16_t port6;
173 uint16_t port7;
174};
175
176struct wccp2_cache_identity_info_t
177{
178
179 struct IN_ADDR addr;
180 uint16_t hash_revision;
181 char bits[2];
182 char buckets[32];
183 uint16_t weight;
184 uint16_t status;
185};
186
187/* Web Cache identity info */
188
189struct wccp2_identity_info_t
190{
191 uint16_t cache_identity_type;
192 uint16_t cache_identity_length;
193
194 struct wccp2_cache_identity_info_t cache_identity;
195};
196
197static struct wccp2_identity_info_t wccp2_identity_info;
198
b7d249f9 199struct wccp2_cache_mask_identity_info_t
200{
201
202 struct IN_ADDR addr;
203 uint32_t num1;
204 uint32_t num2;
205 uint32_t source_ip_mask;
206 uint32_t dest_ip_mask;
207 uint16_t source_port_mask;
208 uint16_t dest_port_mask;
209 uint32_t num3;
210 uint32_t num4;
211};
212
213/* Web Cache identity info */
214
215struct wccp2_mask_identity_info_t
216{
217 uint16_t cache_identity_type;
218 uint16_t cache_identity_length;
219
220 struct wccp2_cache_mask_identity_info_t cache_identity;
221};
222
223static struct wccp2_mask_identity_info_t wccp2_mask_identity_info;
224
0b0cfcf2 225/* View header */
226
227struct wccp2_cache_view_header_t
228{
229 uint16_t cache_view_type;
230 uint16_t cache_view_length;
231 uint32_t cache_view_version;
232};
233
234static struct wccp2_cache_view_header_t wccp2_cache_view_header;
235
236/* View info */
237
238struct wccp2_cache_view_info_t
239{
240 uint32_t num_routers;
241 uint32_t num_caches;
242};
243
244static struct wccp2_cache_view_info_t wccp2_cache_view_info;
245
246/* Router ID element */
247
248struct wccp2_router_id_element_t
249{
250
251 struct IN_ADDR router_address;
252 uint32_t received_id;
253};
254
255static struct wccp2_router_id_element_t wccp2_router_id_element;
256
257/* Capability info header */
258
259struct wccp2_capability_info_header_t
260{
261 uint16_t capability_info_type;
262 uint16_t capability_info_length;
263};
264
265static struct wccp2_capability_info_header_t wccp2_capability_info_header;
266
c1f55201 267/* Capability element header */
268
269struct wccp2_capability_element_header_t
270{
271 uint16_t capability_type;
272 uint16_t capability_length;
273};
274
0b0cfcf2 275/* Capability element */
276
277struct wccp2_capability_element_t
278{
279 uint16_t capability_type;
280 uint16_t capability_length;
281 uint32_t capability_value;
282};
283
284static struct wccp2_capability_element_t wccp2_capability_element;
285
b7d249f9 286/* Mask Element */
287
288struct wccp2_mask_element_t
289{
290 uint32_t source_ip_mask;
291 uint32_t dest_ip_mask;
292 uint16_t source_port_mask;
293 uint16_t dest_port_mask;
294 uint32_t number_values;
295};
296
297/* Value Element */
298
299struct wccp2_value_element_t
300{
301 uint32_t source_ip_value;
302 uint32_t dest_ip_value;
303 uint16_t source_port_value;
304 uint16_t dest_port_value;
305
306 struct IN_ADDR cache_ip;
307};
0b0cfcf2 308
309/* RECEIVED PACKET STRUCTURE */
310
311struct wccp2_i_see_you_t
312{
313 uint32_t type;
314 uint16_t version;
315 uint16_t length;
316 char data[WCCP_RESPONSE_SIZE];
317};
318
319static struct wccp2_i_see_you_t wccp2_i_see_you;
320
321/* Router ID element */
322
323struct wccp2_router_assign_element_t
324{
325
326 struct IN_ADDR router_address;
327 uint32_t received_id;
328 uint32_t change_number;
329};
330
331/* Generic header struct */
332
333struct wccp2_item_header_t
334{
335 uint16_t type;
336 uint16_t length;
337};
338
339/* Router identity struct */
340
341struct router_identity_info_t
342{
343
344 struct wccp2_item_header_t header;
345
346 struct wccp2_router_id_element_t router_id_element;
347
348 struct IN_ADDR router_address;
349 uint32_t number_caches;
350};
351
b7d249f9 352/* The received packet for a mask assignment is unusual */
353
354struct cache_mask_info_t
355{
356
357 struct IN_ADDR addr;
358 uint32_t num1;
359 uint32_t num2;
360 uint32_t num3;
361};
362
0b0cfcf2 363/* assigment key */
364
365struct assignment_key_t
366{
367
368 struct IN_ADDR master_ip;
369 uint32_t master_number;
370};
371
372/* Router view of WCCP */
373
374struct router_view_t
375{
376
377 struct wccp2_item_header_t header;
378 uint32_t change_number;
379
380 struct assignment_key_t assignment_key;
381};
382
0b0cfcf2 383/* Lists used to keep track of caches, routers and services */
384
385struct wccp2_cache_list_t
386{
387
388 struct IN_ADDR cache_ip;
389
f16fbc82 390 int weight;
391
0b0cfcf2 392 struct wccp2_cache_list_t *next;
393};
394
395struct wccp2_router_list_t
396{
397
398 struct wccp2_router_id_element_t *info;
399
400 struct IN_ADDR local_ip;
401
402 struct IN_ADDR router_sendto_address;
403 uint32_t member_change;
404 uint32_t num_caches;
405
406 struct wccp2_cache_list_t cache_list_head;
407
408 struct wccp2_router_list_t *next;
409};
410
411static int wccp2_numrouters;
412
413struct wccp2_service_list_t
414{
415
416 struct wccp2_service_info_t info;
417 uint32_t num_routers;
418
419 struct wccp2_router_list_t router_list_head;
420 int lowest_ip;
421 uint32_t change_num;
422
b7d249f9 423 char *wccp2_identity_info_ptr;
424 ;
0b0cfcf2 425
426 struct wccp2_security_md5_t *security_info;
427
428 struct wccp2_service_info_t *service_info;
429 char wccp_packet[WCCP_RESPONSE_SIZE];
430 size_t wccp_packet_size;
431
432 struct wccp2_service_list_t *next;
433 char wccp_password[WCCP2_PASSWORD_LEN + 1]; /* hold the trailing C-string NUL */
434 uint32_t wccp2_security_type;
435};
436
437static struct wccp2_service_list_t *wccp2_service_list_head = NULL;
438
439int empty_portlist[WCCP2_NUMPORTS] =
440 {0, 0, 0, 0, 0, 0, 0, 0};
441
442/* END WCCP V2 */
443void wccp2_add_service_list(int service, int service_id, int service_priority,
444 int service_proto, int service_flags, int ports[], int security_type, char *password);
445
446/*
447 * The functions used during startup:
448 * wccp2Init
449 * wccp2ConnectionOpen
450 * wccp2ConnectionClose
451 */
452
453static void
454wccp2InitServices(void)
455{
456 debug(80, 5) ("wccp2InitServices: called\n");
457}
458
459static void
460
461wccp2_update_service(struct wccp2_service_list_t *srv, int service,
462 int service_id, int service_priority, int service_proto, int service_flags,
463 int ports[])
464{
465 /* XXX check what needs to be wrapped in htons()! */
466 srv->info.service = service;
467 srv->info.service_id = service_id;
468 srv->info.service_priority = service_priority;
469 srv->info.service_protocol = service_proto;
470 srv->info.service_flags = htonl(service_flags);
471 srv->info.port0 = htons(ports[0]);
472 srv->info.port1 = htons(ports[1]);
473 srv->info.port2 = htons(ports[2]);
474 srv->info.port3 = htons(ports[3]);
475 srv->info.port4 = htons(ports[4]);
476 srv->info.port5 = htons(ports[5]);
477 srv->info.port6 = htons(ports[6]);
478 srv->info.port7 = htons(ports[7]);
479}
480
481void
482wccp2_add_service_list(int service, int service_id, int service_priority,
483 int service_proto, int service_flags, int ports[], int security_type,
484 char *password)
485{
486
487 struct wccp2_service_list_t *wccp2_service_list_ptr;
488
489 wccp2_service_list_ptr = (wccp2_service_list_t *) xcalloc(1, sizeof(struct wccp2_service_list_t));
490
491 debug(80, 5) ("wccp2_add_service_list: added service id %d\n", service_id);
492
493 /* XXX check what needs to be wrapped in htons()! */
494 wccp2_service_list_ptr->info.service_type = htons(WCCP2_SERVICE_INFO);
495
496 wccp2_service_list_ptr->info.service_length = htons(sizeof(struct wccp2_service_info_t) - 4);
497 wccp2_service_list_ptr->change_num = 0;
498 wccp2_update_service(wccp2_service_list_ptr, service, service_id,
499 service_priority, service_proto, service_flags, ports);
500 wccp2_service_list_ptr->wccp2_security_type = security_type;
a302ad3c 501 memset(wccp2_service_list_ptr->wccp_password, 0, WCCP2_PASSWORD_LEN + 1);
0b0cfcf2 502 strncpy(wccp2_service_list_ptr->wccp_password, password, WCCP2_PASSWORD_LEN);
503 /* add to linked list - XXX this should use the Squid dlink* routines! */
504 wccp2_service_list_ptr->next = wccp2_service_list_head;
505 wccp2_service_list_head = wccp2_service_list_ptr;
506}
507
508static struct wccp2_service_list_t *
509 wccp2_get_service_by_id(int service, int service_id)
510{
511
512 struct wccp2_service_list_t *p;
513
514 p = wccp2_service_list_head;
515
516 while (p != NULL)
517 {
518 if (p->info.service == service && p->info.service_id == service_id) {
519 return p;
520 }
521
522 p = p->next;
523 }
524
525 return NULL;
526}
527
528/*
529 * Update the md5 security header, if possible
530 *
531 * Returns: 1 if we set it, 0 if not (eg, no security section, or non-md5)
532 */
533static char
534wccp2_update_md5_security(char *password, char *ptr, char *packet, int len)
535{
536 u_int8_t md5_digest[16];
537 char pwd[WCCP2_PASSWORD_LEN];
538 MD5_CTX M;
539
540 struct wccp2_security_md5_t *ws;
541
542 debug(80, 5) ("wccp2_update_md5_security: called\n");
543
544 /* The password field, for the MD5 hash, needs to be 8 bytes and NUL padded. */
a302ad3c 545 memset(pwd, 0, sizeof(pwd));
0b0cfcf2 546 strncpy(pwd, password, sizeof(pwd));
547
548 ws = (struct wccp2_security_md5_t *) ptr;
549 assert(ntohs(ws->security_type) == WCCP2_SECURITY_INFO);
550 /* Its the security part */
551
552 if (ntohl(ws->security_option) != WCCP2_MD5_SECURITY) {
553 debug(80, 5) ("wccp2_update_md5_security: this service ain't md5'ing, abort\n");
554 return 0;
555 }
556
557 /* And now its the MD5 section! */
558 /* According to the draft, the MD5 security hash is the combination of
559 * the 8-octet password (padded w/ NUL bytes) and the entire WCCP packet,
560 * including the WCCP message header. The WCCP security implementation
561 * area should be zero'ed before calculating the MD5 hash.
562 */
563 /* XXX eventually we should be able to kill md5_digest and blit it directly in */
a302ad3c 564 memset(ws->security_implementation, 0, sizeof(ws->security_implementation));
0b0cfcf2 565
566 MD5Init(&M);
567
568 MD5Update(&M, pwd, 8);
569
570 MD5Update(&M, packet, len);
571
572 MD5Final(md5_digest, &M);
573
574 memcpy(ws->security_implementation, md5_digest, sizeof(md5_digest));
575
576 /* Finished! */
577 return 1;
578}
579
580
581/*
582 * Check the given WCCP2 packet against the given password.
583 */
584static char
585
586wccp2_check_security(struct wccp2_service_list_t *srv, char *security, char *packet, int len)
587{
588
589 struct wccp2_security_md5_t *ws = (struct wccp2_security_md5_t *) security;
590 u_int8_t md5_digest[16], md5_challenge[16];
591 char pwd[WCCP2_PASSWORD_LEN];
592 MD5_CTX M;
593
594 /* Make sure the security type matches what we expect */
595
596 if (ntohl(ws->security_option) != srv->wccp2_security_type)
597 {
598 debug(80, 1) ("wccp2_check_security: received packet has the wrong security option\n");
599 return 0;
600 }
601
602 if (srv->wccp2_security_type == WCCP2_NO_SECURITY)
603 {
604 return 1;
605 }
606
607 if (srv->wccp2_security_type != WCCP2_MD5_SECURITY)
608 {
609 debug(80, 1) ("wccp2_check_security: invalid security option\n");
610 return 0;
611 }
612
613 /* If execution makes it here then we have an MD5 security */
614
615 /* The password field, for the MD5 hash, needs to be 8 bytes and NUL padded. */
a302ad3c 616 memset(pwd, 0, sizeof(pwd));
0b0cfcf2 617
618 strncpy(pwd, srv->wccp_password, sizeof(pwd));
619
620 /* Take a copy of the challenge: we need to NUL it before comparing */
621 memcpy(md5_challenge, ws->security_implementation, 16);
622
a302ad3c 623 memset(ws->security_implementation, 0, sizeof(ws->security_implementation));
0b0cfcf2 624
625 MD5Init(&M);
626
627 MD5Update(&M, pwd, 8);
628
629 MD5Update(&M, packet, len);
630
631 MD5Final(md5_digest, &M);
632
633 return (memcmp(md5_digest, md5_challenge, 16) == 0);
634}
635
636
637void
638wccp2Init(void)
639{
640 sockaddr_in_list *s;
641 char *ptr;
b7d249f9 642 uint32_t service_flags;
0b0cfcf2 643
644 struct wccp2_service_list_t *service_list_ptr;
645
646 struct wccp2_router_list_t *router_list_ptr;
647
648 struct wccp2_security_md5_t wccp2_security_md5;
649
650 debug(80, 5) ("wccp2Init: Called\n");
651
652 if (wccp2_connected == 1)
653 return;
654
655 wccp2_numrouters = 0;
656
657 /* Calculate the number of routers configured in the config file */
658 for (s = Config.Wccp2.router; s; s = s->next) {
659 if (s->s.sin_addr.s_addr != any_addr.s_addr) {
660 /* Increment the counter */
661 wccp2_numrouters++;
662 }
663 }
664
665 if (wccp2_numrouters == 0) {
666 return;
667 }
668
669 /* Initialise the list of services */
670 wccp2InitServices();
671
672 service_list_ptr = wccp2_service_list_head;
673
674 while (service_list_ptr != NULL) {
675 /* Set up our list pointers */
676 router_list_ptr = &service_list_ptr->router_list_head;
677
678 /* start the wccp header */
679 wccp2_here_i_am_header.type = htonl(WCCP2_HERE_I_AM);
680 wccp2_here_i_am_header.version = htons(WCCP2_VERSION);
681 wccp2_here_i_am_header.length = 0;
682 ptr = service_list_ptr->wccp_packet + sizeof(wccp2_here_i_am_header);
683
684 /* add the security section */
685 /* XXX this is ugly */
686
687 if (service_list_ptr->wccp2_security_type == WCCP2_MD5_SECURITY) {
688 wccp2_security_md5.security_option = htonl(WCCP2_MD5_SECURITY);
689
690 wccp2_security_md5.security_length = htons(sizeof(struct wccp2_security_md5_t) - 4);
691 } else if (service_list_ptr->wccp2_security_type == WCCP2_NO_SECURITY) {
692 wccp2_security_md5.security_option = htonl(WCCP2_NO_SECURITY);
693 /* XXX I hate magic length numbers! */
694 wccp2_security_md5.security_length = htons(4);
695 } else {
696 fatalf("Bad WCCP2 security type\n");
697 }
698
699 wccp2_here_i_am_header.length += ntohs(wccp2_security_md5.security_length) + 4;
700 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
701 wccp2_security_md5.security_type = htons(WCCP2_SECURITY_INFO);
702
703 service_list_ptr->security_info = (struct wccp2_security_md5_t *) ptr;
704
705 if (service_list_ptr->wccp2_security_type == WCCP2_MD5_SECURITY) {
706
707 xmemcpy(ptr, &wccp2_security_md5, sizeof(struct wccp2_security_md5_t));
708
709 ptr += sizeof(struct wccp2_security_md5_t);
710 } else {
711 /* assume NONE, and XXX I hate magic length numbers */
712 xmemcpy(ptr, &wccp2_security_md5, 8);
713 ptr += 8;
714 }
715
716 /* Add the service info section */
717
718 wccp2_here_i_am_header.length += sizeof(struct wccp2_service_info_t);
719
720 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
721
722 xmemcpy(ptr, &service_list_ptr->info, sizeof(struct wccp2_service_info_t));
723
724 service_list_ptr->service_info = (struct wccp2_service_info_t *) ptr;
725
726 ptr += sizeof(struct wccp2_service_info_t);
727
728 /* Add the cache identity section */
729
b7d249f9 730 switch (Config.Wccp2.assignment_method) {
0b0cfcf2 731
b7d249f9 732 case WCCP2_ASSIGNMENT_METHOD_HASH:
0b0cfcf2 733
b7d249f9 734 wccp2_here_i_am_header.length += sizeof(struct wccp2_identity_info_t);
735 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
736 wccp2_identity_info.cache_identity_type = htons(WCCP2_WC_ID_INFO);
737 wccp2_identity_info.cache_identity_length = htons(sizeof(wccp2_identity_info.cache_identity));
738 memset(&wccp2_identity_info.cache_identity.addr, '\0', sizeof(wccp2_identity_info.cache_identity.addr));
739 memset(&wccp2_identity_info.cache_identity.hash_revision, '\0', sizeof(wccp2_identity_info.cache_identity.hash_revision));
740 memset(&wccp2_identity_info.cache_identity.bits, '\0', sizeof(wccp2_identity_info.cache_identity.bits));
741 memset(&wccp2_identity_info.cache_identity.buckets, '\0', sizeof(wccp2_identity_info.cache_identity.buckets));
742 wccp2_identity_info.cache_identity.weight = htons(Config.Wccp2.weight);
743 memset(&wccp2_identity_info.cache_identity.status, '\0', sizeof(wccp2_identity_info.cache_identity.status));
0b0cfcf2 744
b7d249f9 745 xmemcpy(ptr, &wccp2_identity_info, sizeof(struct wccp2_identity_info_t));
746 service_list_ptr->wccp2_identity_info_ptr = ptr;
0b0cfcf2 747
b7d249f9 748 ptr += sizeof(struct wccp2_identity_info_t);
749 break;
0b0cfcf2 750
b7d249f9 751 case WCCP2_ASSIGNMENT_METHOD_MASK:
752
753 wccp2_here_i_am_header.length += sizeof(struct wccp2_mask_identity_info_t);
754 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
755 wccp2_mask_identity_info.cache_identity_type = htons(WCCP2_WC_ID_INFO);
756 wccp2_mask_identity_info.cache_identity_length = htons(sizeof(wccp2_mask_identity_info.cache_identity));
757 memset(&wccp2_mask_identity_info.cache_identity.addr, '\0', sizeof(wccp2_mask_identity_info.cache_identity.addr));
758 wccp2_mask_identity_info.cache_identity.num1 = htonl(2);
759 wccp2_mask_identity_info.cache_identity.num2 = htonl(1);
760 service_flags = ntohl(service_list_ptr->service_info->service_flags);
761
762 if ((service_flags & WCCP2_SERVICE_SRC_IP_HASH) || (service_flags & WCCP2_SERVICE_SRC_IP_ALT_HASH)) {
763 wccp2_mask_identity_info.cache_identity.source_ip_mask = htonl(0x00001741);
764 wccp2_mask_identity_info.cache_identity.dest_ip_mask = 0;
765 wccp2_mask_identity_info.cache_identity.source_port_mask = 0;
766 wccp2_mask_identity_info.cache_identity.dest_port_mask = 0;
767 } 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)) {
768 wccp2_mask_identity_info.cache_identity.source_ip_mask = 0;
769 wccp2_mask_identity_info.cache_identity.dest_ip_mask = htonl(0x00001741);
770 wccp2_mask_identity_info.cache_identity.source_port_mask = 0;
771 wccp2_mask_identity_info.cache_identity.dest_port_mask = 0;
772 } else if ((service_flags & WCCP2_SERVICE_SRC_PORT_HASH) || (service_flags & WCCP2_SERVICE_SRC_PORT_ALT_HASH)) {
773 wccp2_mask_identity_info.cache_identity.source_ip_mask = 0;
774 wccp2_mask_identity_info.cache_identity.dest_ip_mask = 0;
775 wccp2_mask_identity_info.cache_identity.source_port_mask = htons(0x1741);
776 wccp2_mask_identity_info.cache_identity.dest_port_mask = 0;
777 } else if ((service_flags & WCCP2_SERVICE_DST_PORT_HASH) || (service_flags & WCCP2_SERVICE_DST_PORT_ALT_HASH)) {
778 wccp2_mask_identity_info.cache_identity.source_ip_mask = 0;
779 wccp2_mask_identity_info.cache_identity.dest_ip_mask = 0;
780 wccp2_mask_identity_info.cache_identity.source_port_mask = 0;
781 wccp2_mask_identity_info.cache_identity.dest_port_mask = htons(0x1741);
782 } else {
783 fatalf("Unknown service hash method\n");
784 }
0b0cfcf2 785
b7d249f9 786 wccp2_mask_identity_info.cache_identity.num3 = 0;
787 wccp2_mask_identity_info.cache_identity.num4 = 0;
0b0cfcf2 788
b7d249f9 789 xmemcpy(ptr, &wccp2_mask_identity_info, sizeof(struct wccp2_mask_identity_info_t));
790 service_list_ptr->wccp2_identity_info_ptr = ptr;
0b0cfcf2 791
b7d249f9 792 ptr += sizeof(struct wccp2_mask_identity_info_t);
793 break;
0b0cfcf2 794
b7d249f9 795 default:
796 fatalf("Unknown Wccp2 assignment method\n");
797 }
0b0cfcf2 798
799 /* Add the cache view section */
800 wccp2_here_i_am_header.length += sizeof(wccp2_cache_view_header);
801
802 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
803
804 wccp2_cache_view_header.cache_view_type = htons(WCCP2_WC_VIEW_INFO);
805
806 wccp2_cache_view_header.cache_view_length = htons(sizeof(wccp2_cache_view_header) - 4 +
807 sizeof(wccp2_cache_view_info) + (wccp2_numrouters * sizeof(wccp2_router_id_element)));
808
809 wccp2_cache_view_header.cache_view_version = htonl(1);
810
811 xmemcpy(ptr, &wccp2_cache_view_header, sizeof(wccp2_cache_view_header));
812
813 ptr += sizeof(wccp2_cache_view_header);
814
815 /* Add the number of routers to the packet */
816 wccp2_here_i_am_header.length += sizeof(service_list_ptr->num_routers);
817
818 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
819
820 service_list_ptr->num_routers = htonl(wccp2_numrouters);
821
822 xmemcpy(ptr, &service_list_ptr->num_routers, sizeof(service_list_ptr->num_routers));
823
824 ptr += sizeof(service_list_ptr->num_routers);
825
826 /* Add each router. Keep this functionality here to make sure the received_id can be updated in the packet */
827 for (s = Config.Wccp2.router; s; s = s->next) {
828 if (s->s.sin_addr.s_addr != any_addr.s_addr) {
829
830 wccp2_here_i_am_header.length += sizeof(struct wccp2_router_id_element_t);
831 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
832
833 /* Add a pointer to the router list for this router */
834
835 router_list_ptr->info = (struct wccp2_router_id_element_t *) ptr;
836 router_list_ptr->info->router_address = s->s.sin_addr;
837 router_list_ptr->info->received_id = htonl(0);
838 router_list_ptr->router_sendto_address = s->s.sin_addr;
839 router_list_ptr->member_change = htonl(0);
840
841 /* Build the next struct */
842
843 router_list_ptr->next = (wccp2_router_list_t*) xcalloc(1, sizeof(struct wccp2_router_list_t));
844
845 /* update the pointer */
846 router_list_ptr = router_list_ptr->next;
847 router_list_ptr->next = NULL;
848
849 /* no need to copy memory - we've just set the values directly in the packet above */
850
851 ptr += sizeof(struct wccp2_router_id_element_t);
852 }
853 }
854
855 /* Add the number of caches (0) */
856 wccp2_here_i_am_header.length += sizeof(wccp2_cache_view_info.num_caches);
857
858 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
859
860 wccp2_cache_view_info.num_caches = htonl(0);
861
862 xmemcpy(ptr, &wccp2_cache_view_info.num_caches, sizeof(wccp2_cache_view_info.num_caches));
863
864 ptr += sizeof(wccp2_cache_view_info.num_caches);
865
866 /* Add the extra capability header */
867 wccp2_here_i_am_header.length += sizeof(wccp2_capability_info_header);
868
869 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
870
871 wccp2_capability_info_header.capability_info_type = htons(WCCP2_CAPABILITY_INFO);
872
c1f55201 873 wccp2_capability_info_header.capability_info_length = htons(3 * sizeof(wccp2_capability_element));
0b0cfcf2 874
875 xmemcpy(ptr, &wccp2_capability_info_header, sizeof(wccp2_capability_info_header));
876
877 ptr += sizeof(wccp2_capability_info_header);
878
879 /* Add the forwarding method */
880 wccp2_here_i_am_header.length += sizeof(wccp2_capability_element);
881
882 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
883
884 wccp2_capability_element.capability_type = htons(WCCP2_CAPABILITY_FORWARDING_METHOD);
885
886 wccp2_capability_element.capability_length = htons(sizeof(wccp2_capability_element.capability_value));
887
888 wccp2_capability_element.capability_value = htonl(Config.Wccp2.forwarding_method);
889
890 xmemcpy(ptr, &wccp2_capability_element, sizeof(wccp2_capability_element));
891
892 ptr += sizeof(wccp2_capability_element);
893
c1f55201 894 /* Add the assignment method */
895 wccp2_here_i_am_header.length += sizeof(wccp2_capability_element);
896
897 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
898
899 wccp2_capability_element.capability_type = htons(WCCP2_CAPABILITY_ASSIGNMENT_METHOD);
900
901 wccp2_capability_element.capability_length = htons(sizeof(wccp2_capability_element.capability_value));
902
b7d249f9 903 wccp2_capability_element.capability_value = htonl(Config.Wccp2.assignment_method);
c1f55201 904
905 xmemcpy(ptr, &wccp2_capability_element, sizeof(wccp2_capability_element));
906
907 ptr += sizeof(wccp2_capability_element);
908
0b0cfcf2 909 /* Add the return method */
910 wccp2_here_i_am_header.length += sizeof(wccp2_capability_element);
911
912 assert(wccp2_here_i_am_header.length <= WCCP_RESPONSE_SIZE);
913
914 wccp2_capability_element.capability_type = htons(WCCP2_CAPABILITY_RETURN_METHOD);
915
916 wccp2_capability_element.capability_length = htons(sizeof(wccp2_capability_element.capability_value));
917
918 wccp2_capability_element.capability_value = htonl(Config.Wccp2.return_method);
919
920 xmemcpy(ptr, &wccp2_capability_element, sizeof(wccp2_capability_element));
921
922 ptr += sizeof(wccp2_capability_element);
923
924 /* Finally, fix the total length to network order, and copy to the appropriate memory blob */
925 wccp2_here_i_am_header.length = htons(wccp2_here_i_am_header.length);
926
927 memcpy(&service_list_ptr->wccp_packet, &wccp2_here_i_am_header, sizeof(wccp2_here_i_am_header));
928
929 service_list_ptr->wccp_packet_size = ntohs(wccp2_here_i_am_header.length) + sizeof(wccp2_here_i_am_header);
930
931 /* Add the event if everything initialised correctly */
932 if (wccp2_numrouters) {
933 if (!eventFind(wccp2HereIam, NULL)) {
934 eventAdd("wccp2HereIam", wccp2HereIam, NULL, 1, 1);
935 }
936 }
937
938 service_list_ptr = service_list_ptr->next;
939 }
940}
941
942void
943wccp2ConnectionOpen(void)
944{
945 u_short port = WCCP_PORT;
946
c1f55201 947 struct sockaddr_in router, local, null;
0b0cfcf2 948 socklen_t local_len, router_len;
949
950 struct wccp2_service_list_t *service_list_ptr;
951
952 struct wccp2_router_list_t *router_list_ptr;
953
954 debug(80, 5) ("wccp2ConnectionOpen: Called\n");
955
956 if (wccp2_numrouters == 0 || !wccp2_service_list_head) {
957 debug(80, 2) ("WCCPv2 Disabled.\n");
958 return;
959 }
960
961 theWccp2Connection = comm_open(SOCK_DGRAM,
962 0,
963 Config.Wccp2.address,
964 port,
965 COMM_NONBLOCKING,
966 "WCCPv2 Socket");
967
968 if (theWccp2Connection < 0)
969 fatal("Cannot open WCCP Port");
970
85d25b95 971#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
972 {
973 int i = IP_PMTUDISC_DONT;
974 setsockopt(theWccp2Connection, SOL_IP, IP_MTU_DISCOVER, &i, sizeof i);
975 }
976
977#endif
0b0cfcf2 978 commSetSelect(theWccp2Connection,
979 COMM_SELECT_READ,
980 wccp2HandleUdp,
981 NULL,
982 0);
983
984 debug(80, 1) ("Accepting WCCPv2 messages on port %d, FD %d.\n",
985 (int) port, theWccp2Connection);
986
987 debug(80, 1) ("Initialising all WCCPv2 lists\n");
988
989 /* Initialise all routers on all services */
c1f55201 990 memset(&null, 0, sizeof(null));
991
992 null.sin_family = AF_UNSPEC;
993
0b0cfcf2 994 service_list_ptr = wccp2_service_list_head;
995
996 while (service_list_ptr != NULL) {
997 for (router_list_ptr = &service_list_ptr->router_list_head; router_list_ptr->next != NULL; router_list_ptr = router_list_ptr->next) {
998 router_len = sizeof(router);
999 memset(&router, '\0', router_len);
1000 router.sin_family = AF_INET;
1001 router.sin_port = htons(port);
1002 router.sin_addr = router_list_ptr->router_sendto_address;
1003
1004 if (connect(theWccp2Connection, (struct sockaddr *) &router, router_len))
1005 fatal("Unable to connect WCCP out socket");
1006
1007 local_len = sizeof(local);
1008
1009 memset(&local, '\0', local_len);
1010
1011 if (getsockname(theWccp2Connection, (struct sockaddr *) &local, &local_len))
1012 fatal("Unable to getsockname on WCCP out socket");
1013
1014 router_list_ptr->local_ip = local.sin_addr;
1015
c1f55201 1016 /* Disconnect the sending socket. Note: FreeBSD returns error
1017 * but disconnects anyway so we have to just assume it worked
1018 */
1019 if (wccp2_numrouters > 1)
0b0cfcf2 1020
c1f55201 1021 connect(theWccp2Connection, (struct sockaddr *) &null, router_len);
0b0cfcf2 1022 }
1023
1024 service_list_ptr = service_list_ptr->next;
1025 }
1026
0b0cfcf2 1027 wccp2_connected = 1;
1028}
1029
1030void
1031wccp2ConnectionClose(void)
1032{
1033
1034 struct wccp2_service_list_t *service_list_ptr;
1035
1036 struct wccp2_service_list_t *service_list_ptr_next;
1037
1038 struct wccp2_router_list_t *router_list_ptr;
1039
1040 struct wccp2_router_list_t *router_list_next;
1041
1042 struct wccp2_cache_list_t *cache_list_ptr;
1043
1044 struct wccp2_cache_list_t *cache_list_ptr_next;
1045
1046 if (wccp2_connected == 0) {
1047 return;
1048 }
1049
1050 if (theWccp2Connection > -1) {
1051 debug(80, 1) ("FD %d Closing WCCP socket\n", theWccp2Connection);
1052 comm_close(theWccp2Connection);
1053 theWccp2Connection = -1;
1054 }
1055
1056 /* for each router on each service send a packet */
1057 service_list_ptr = wccp2_service_list_head;
1058
1059 while (service_list_ptr != NULL) {
1060 for (router_list_ptr = &service_list_ptr->router_list_head; router_list_ptr != NULL; router_list_ptr = router_list_next) {
1061 for (cache_list_ptr = &router_list_ptr->cache_list_head; cache_list_ptr; cache_list_ptr = cache_list_ptr_next) {
1062 cache_list_ptr_next = cache_list_ptr->next;
1063
1064 if (cache_list_ptr != &router_list_ptr->cache_list_head) {
1065 xfree(cache_list_ptr);
1066 } else {
1067
1068 memset(cache_list_ptr, '\0', sizeof(struct wccp2_cache_list_t));
1069 }
1070 }
1071
1072 router_list_next = router_list_ptr->next;
1073
1074 if (router_list_ptr != &service_list_ptr->router_list_head) {
1075 xfree(router_list_ptr);
1076 } else {
1077
1078 memset(router_list_ptr, '\0', sizeof(struct wccp2_router_list_t));
1079 }
1080 }
1081
1082 service_list_ptr_next = service_list_ptr->next;
1083 xfree(service_list_ptr);
1084 service_list_ptr = service_list_ptr_next;
1085 }
1086
1087 wccp2_service_list_head = NULL;
1088 eventDelete(wccp2HereIam, NULL);
1089 eventDelete(wccp2AssignBuckets, NULL);
1090 eventDelete(wccp2HereIam, NULL);
1091 wccp2_connected = 0;
1092}
1093
1094/*
1095 * Functions for handling the requests.
1096 */
1097
1098/*
1099 * Accept the UDP packet
1100 */
1101static void
1102wccp2HandleUdp(int sock, void *not_used)
1103{
1104
1105 struct wccp2_service_list_t *service_list_ptr;
1106
1107 struct wccp2_router_list_t *router_list_ptr;
1108
1109 struct wccp2_cache_list_t *cache_list_ptr;
1110
1111 struct wccp2_cache_list_t *cache_list_ptr_next;
1112
1113 /* These structs form the parts of the packet */
1114
1115 struct wccp2_item_header_t *header = NULL;
1116
1117 struct wccp2_security_none_t *security_info = NULL;
1118
1119 struct wccp2_service_info_t *service_info = NULL;
1120
1121 struct router_identity_info_t *router_identity_info = NULL;
1122
1123 struct router_view_t *router_view_header = NULL;
1124
b7d249f9 1125 struct wccp2_cache_mask_identity_info_t *cache_mask_identity = NULL;
1126
1127 struct cache_mask_info_t *cache_mask_info = NULL;
1128
0b0cfcf2 1129 struct wccp2_cache_identity_info_t *cache_identity = NULL;
1130
1131 struct wccp2_capability_info_header_t *router_capability_header = NULL;
1132
1133 struct wccp2_capability_element_t *router_capability_element;
1134
1135 struct sockaddr_in from;
1136
1137 struct IN_ADDR cache_address;
1138 socklen_t from_len;
1139 int len, found;
1140 short int data_length, offset;
1141 uint32_t tmp;
1142 char *ptr;
1143 int num_caches;
0b0cfcf2 1144
1145 debug(80, 6) ("wccp2HandleUdp: Called.\n");
1146
1147 commSetSelect(sock, COMM_SELECT_READ, wccp2HandleUdp, NULL, 0);
1148
1149 from_len = sizeof(struct sockaddr_in);
1150 memset(&from, '\0', from_len);
1151
1152 len = comm_udp_recvfrom(sock,
1153 &wccp2_i_see_you,
1154 WCCP_RESPONSE_SIZE,
1155 0,
1156
1157 (struct sockaddr *) &from,
1158 &from_len);
1159
1160 if (len < 0)
1161 return;
1162
1163 if (ntohs(wccp2_i_see_you.version) != WCCP2_VERSION)
1164 return;
1165
1166 if (ntohl(wccp2_i_see_you.type) != WCCP2_I_SEE_YOU)
1167 return;
1168
1169 debug(80, 3) ("Incoming WCCPv2 I_SEE_YOU length %d.\n", ntohs(wccp2_i_see_you.length));
1170
1171 /* Record the total data length */
1172 data_length = ntohs(wccp2_i_see_you.length);
1173
1174 offset = 0;
1175
1176 if (data_length > len) {
1177 debug(80, 1) ("ERROR: Malformed WCCPv2 packet claiming it's bigger than received data\n");
1178 return;
1179 }
1180
1181 /* Go through the data structure */
1182 while (data_length > offset) {
1183
1184 header = (struct wccp2_item_header_t *) &wccp2_i_see_you.data[offset];
1185
1186 switch (ntohs(header->type)) {
1187
1188 case WCCP2_SECURITY_INFO:
1189
1190 if (security_info != NULL) {
1191 debug(80, 1) ("Duplicate security definition\n");
1192 return;
1193 }
1194
1195 security_info = (struct wccp2_security_none_t *) &wccp2_i_see_you.data[offset];
1196 break;
1197
1198 case WCCP2_SERVICE_INFO:
1199
1200 if (service_info != NULL) {
1201 debug(80, 1) ("Duplicate service_info definition\n");
1202 return;
1203 }
1204
1205 service_info = (struct wccp2_service_info_t *) &wccp2_i_see_you.data[offset];
1206 break;
1207
1208 case WCCP2_ROUTER_ID_INFO:
1209
1210 if (router_identity_info != NULL) {
1211 debug(80, 1) ("Duplicate router_identity_info definition\n");
1212 return;
1213 }
1214
1215 router_identity_info = (struct router_identity_info_t *) &wccp2_i_see_you.data[offset];
1216 break;
1217
1218 case WCCP2_RTR_VIEW_INFO:
1219
1220 if (router_view_header != NULL) {
1221 debug(80, 1) ("Duplicate router_view definition\n");
1222 return;
1223 }
1224
1225 router_view_header = (struct router_view_t *) &wccp2_i_see_you.data[offset];
1226 break;
1227
1228 case WCCP2_CAPABILITY_INFO:
1229
1230 if (router_capability_header != NULL) {
1231 debug(80, 1) ("Duplicate router_capability definition\n");
1232 return;
1233 }
1234
1235 router_capability_header = (struct wccp2_capability_info_header_t *) &wccp2_i_see_you.data[offset];
c1f55201 1236 break;
0b0cfcf2 1237
b7d249f9 1238 /* Nothing to do for the types below */
1239
1240 case WCCP2_ASSIGN_MAP:
1241 break;
1242
0b0cfcf2 1243 default:
1244 debug(80, 1) ("Unknown record type in WCCPv2 Packet (%d).\n",
1245 ntohs(header->type));
1246 }
1247
1248 offset += sizeof(struct wccp2_item_header_t);
1249 offset += ntohs(header->length);
1250
1251 if (offset > data_length) {
1252 debug(80, 1) ("Error: WCCPv2 packet tried to tell us there is data beyond the end of the packet\n");
1253 return;
1254 }
1255 }
1256
1257 if ((security_info == NULL) || (service_info == NULL) || (router_identity_info == NULL) || (router_view_header == NULL)) {
1258 debug(80, 1) ("Incomplete WCCPv2 Packet\n");
1259 return;
1260 }
1261
1262 debug(80, 5) ("Complete packet received\n");
1263
1264 /* Check that the service in the packet is configured on this router */
1265 service_list_ptr = wccp2_service_list_head;
1266
1267 while (service_list_ptr != NULL) {
1268 if (service_info->service_id == service_list_ptr->service_info->service_id) {
1269 break;
1270 }
1271
1272 service_list_ptr = service_list_ptr->next;
1273 }
1274
1275 if (service_list_ptr == NULL) {
1276 debug(80, 1) ("WCCPv2 Unknown service received from router (%d)\n", service_info->service_id);
1277 return;
1278 }
1279
1280 if (ntohl(security_info->security_option) != ntohl(service_list_ptr->security_info->security_option)) {
6013702c 1281 debugs(80, 1, "Invalid security option in WCCPv2 Packet (" << ntohl(security_info->security_option) << " vs " << ntohl(service_list_ptr->security_info->security_option) << ").");
0b0cfcf2 1282 return;
1283 }
1284
1285 if (!wccp2_check_security(service_list_ptr, (char *) security_info, (char *) &wccp2_i_see_you, len)) {
1286 debug(80, 1) ("Received WCCPv2 Packet failed authentication\n");
1287 return;
1288 }
1289
1290 /* Check that the router address is configured on this router */
1291 for (router_list_ptr = &service_list_ptr->router_list_head; router_list_ptr->next != NULL; router_list_ptr = router_list_ptr->next) {
1292 if (router_list_ptr->router_sendto_address.s_addr == from.sin_addr.s_addr)
1293 break;
1294 }
1295
1296 if (router_list_ptr->next == NULL) {
1297 debug(80, 1) ("WCCPv2 Packet received from unknown router\n");
1298 return;
1299 }
1300
1301 /* Set the router id */
1302 router_list_ptr->info->router_address = router_identity_info->router_id_element.router_address;
1303
1304 /* Increment the received id in the packet */
1305 if (ntohl(router_list_ptr->info->received_id) != ntohl(router_identity_info->router_id_element.received_id)) {
6013702c 1306 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) << ".");
0b0cfcf2 1307 router_list_ptr->info->received_id = router_identity_info->router_id_element.received_id;
1308 }
1309
1310 /* TODO: check return/forwarding methods */
1311 if (router_capability_header == NULL) {
c1f55201 1312 if ((Config.Wccp2.return_method != WCCP2_PACKET_RETURN_METHOD_GRE) || (Config.Wccp2.forwarding_method != WCCP2_FORWARDING_METHOD_GRE)) {
1313 debug(80, 1) ("wccp2HandleUdp: fatal error - A WCCP router does not support the forwarding method specified, only GRE supported\n");
0b0cfcf2 1314 wccp2ConnectionClose();
1315 return;
1316 }
1317 } else {
0b0cfcf2 1318
c1f55201 1319 char *end = ((char *) router_capability_header) + sizeof(*router_capability_header) + ntohs(router_capability_header->capability_info_length) - sizeof(struct wccp2_capability_info_header_t);
1320
1321 router_capability_element = (struct wccp2_capability_element_t *) (((char *) router_capability_header) + sizeof(*router_capability_header));
0b0cfcf2 1322
c1f55201 1323 while ((char *) router_capability_element <= end) {
0b0cfcf2 1324
1325 switch (ntohs(router_capability_element->capability_type)) {
1326
1327 case WCCP2_CAPABILITY_FORWARDING_METHOD:
1328
c1f55201 1329 if (!(ntohl(router_capability_element->capability_value) & Config.Wccp2.forwarding_method)) {
6013702c 1330 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);
0b0cfcf2 1331 wccp2ConnectionClose();
1332 return;
1333 }
1334
1335 break;
1336
1337 case WCCP2_CAPABILITY_ASSIGNMENT_METHOD:
c1f55201 1338
b7d249f9 1339 if (!(ntohl(router_capability_element->capability_value) & Config.Wccp2.assignment_method)) {
1340 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);
c1f55201 1341 wccp2ConnectionClose();
1342 return;
1343 }
1344
0b0cfcf2 1345 break;
1346
1347 case WCCP2_CAPABILITY_RETURN_METHOD:
1348
c1f55201 1349 if (!(ntohl(router_capability_element->capability_value) & Config.Wccp2.return_method)) {
6013702c 1350 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);
0b0cfcf2 1351 wccp2ConnectionClose();
1352 return;
1353 }
1354
1355 break;
1356
1357 default:
1358 debug(80, 1) ("Unknown capability type in WCCPv2 Packet (%d).\n",
1359 ntohs(router_capability_element->capability_type));
1360 }
c1f55201 1361
1362 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));
0b0cfcf2 1363 }
1364 }
1365
1366 debug(80, 5) ("Cleaning out cache list\n");
1367 /* clean out the old cache list */
1368
1369 for (cache_list_ptr = &router_list_ptr->cache_list_head; cache_list_ptr; cache_list_ptr = cache_list_ptr_next) {
1370 cache_list_ptr_next = cache_list_ptr->next;
1371
1372 if (cache_list_ptr != &router_list_ptr->cache_list_head) {
1373 xfree(cache_list_ptr);
1374 }
1375 }
1376
1377 router_list_ptr->num_caches = htonl(0);
1378 num_caches = 0;
1379
1380 /* Check to see if we're the master cache and update the cache list */
1381 found = 0;
1382 service_list_ptr->lowest_ip = 1;
1383 cache_list_ptr = &router_list_ptr->cache_list_head;
1384
1385 /* to find the list of caches, we start at the end of the router view header */
1386
1387 ptr = (char *) (router_view_header) + sizeof(struct router_view_t);
1388
1389 /* Then we read the number of routers */
1390 memcpy(&tmp, ptr, sizeof(tmp));
1391
1392 /* skip the number plus all the ip's */
1393
1394 ptr += sizeof(tmp) + (ntohl(tmp) * sizeof(struct IN_ADDR));
1395
1396 /* Then read the number of caches */
1397 memcpy(&tmp, ptr, sizeof(tmp));
1398 ptr += sizeof(tmp);
1399
1400 if (ntohl(tmp) != 0) {
1401 /* search through the list of received-from ip addresses */
1402
1403 for (num_caches = 0; num_caches < (int) ntohl(tmp); num_caches++) {
1404 /* Get a copy of the ip */
1405
b7d249f9 1406 switch (Config.Wccp2.assignment_method) {
1407
1408 case WCCP2_ASSIGNMENT_METHOD_HASH:
1409
1410 cache_identity = (struct wccp2_cache_identity_info_t *) ptr;
1411
1412 ptr += sizeof(struct wccp2_cache_identity_info_t);
1413
1414 memcpy(&cache_address, &cache_identity->addr, sizeof(struct IN_ADDR));
1415
1416 cache_list_ptr->weight = ntohs(cache_identity->weight);
1417 break;
1418
1419 case WCCP2_ASSIGNMENT_METHOD_MASK:
1420
1421 cache_mask_info = (struct cache_mask_info_t *) ptr;
1422
1423 /* The mask assignment has an undocumented variable length entry here */
1424
1425 if (ntohl(cache_mask_info->num1) == 3) {
1426
1427 cache_mask_identity = (struct wccp2_cache_mask_identity_info_t *) ptr;
1428
1429 ptr += sizeof(struct wccp2_cache_mask_identity_info_t);
0b0cfcf2 1430
b7d249f9 1431 memcpy(&cache_address, &cache_mask_identity->addr, sizeof(struct IN_ADDR));
1432 } else {
1433
1434 ptr += sizeof(struct cache_mask_info_t);
1435
1436 memcpy(&cache_address, &cache_mask_info->addr, sizeof(struct IN_ADDR));
1437 }
0b0cfcf2 1438
b7d249f9 1439 cache_list_ptr->weight = 0;
1440 break;
1441
1442 default:
1443 fatalf("Unknown Wccp2 assignment method\n");
1444 }
0b0cfcf2 1445
1446 /* Update the cache list */
1447 cache_list_ptr->cache_ip = cache_address;
b7d249f9 1448
0b0cfcf2 1449 cache_list_ptr->next = (wccp2_cache_list_t*) xcalloc(1, sizeof(struct wccp2_cache_list_t));
b7d249f9 1450
0b0cfcf2 1451 cache_list_ptr = cache_list_ptr->next;
b7d249f9 1452
0b0cfcf2 1453 cache_list_ptr->next = NULL;
1454
1455 debug(80, 5) ("checking cache list: (%x:%x)\n", cache_address.s_addr, router_list_ptr->local_ip.s_addr);
b7d249f9 1456
0b0cfcf2 1457 /* Check to see if it's the master, or us */
1458
1459 if (cache_address.s_addr == router_list_ptr->local_ip.s_addr) {
1460 found = 1;
1461 }
1462
1463 if (cache_address.s_addr < router_list_ptr->local_ip.s_addr) {
1464 service_list_ptr->lowest_ip = 0;
1465 }
1466 }
1467 } else {
b7d249f9 1468 debug(80, 5) ("Adding ourselves as the only cache\n");
0b0cfcf2 1469
1470 /* Update the cache list */
1471 cache_list_ptr->cache_ip = router_list_ptr->local_ip;
1472
1473 cache_list_ptr->next = (wccp2_cache_list_t*) xcalloc(1, sizeof(struct wccp2_cache_list_t));
1474 cache_list_ptr = cache_list_ptr->next;
1475 cache_list_ptr->next = NULL;
1476
b7d249f9 1477 service_list_ptr->lowest_ip = 1;
0b0cfcf2 1478 found = 1;
1479 num_caches = 1;
1480 }
1481
1482 router_list_ptr->num_caches = htonl(num_caches);
1483
1484 if ((found == 1) && (service_list_ptr->lowest_ip == 1)) {
1485 if (ntohl(router_view_header->change_number) != router_list_ptr->member_change) {
1486 debug(80, 4) ("Change detected - queueing up new assignment\n");
1487 router_list_ptr->member_change = ntohl(router_view_header->change_number);
c1f55201 1488 eventDelete(wccp2AssignBuckets, NULL);
1489 eventAdd("wccp2AssignBuckets", wccp2AssignBuckets, NULL, 15.0, 1);
b7d249f9 1490 } else {
b4f8f6b7 1491 debug(80, 5) ("Change not detected (%d = %d)\n", (int) ntohl(router_view_header->change_number), router_list_ptr->member_change);
0b0cfcf2 1492 }
1493 } else {
b7d249f9 1494 eventDelete(wccp2AssignBuckets, NULL);
0b0cfcf2 1495 debug(80, 5) ("I am not the lowest ip cache - not assigning buckets\n");
1496 }
1497}
1498
1499static void
1500wccp2HereIam(void *voidnotused)
1501{
1502
1503 struct wccp2_service_list_t *service_list_ptr;
1504
1505 struct wccp2_router_list_t *router_list_ptr;
1506
b7d249f9 1507 struct wccp2_identity_info_t *wccp2_identity_info_ptr;
1508
1509 struct wccp2_mask_identity_info_t *wccp2_mask_identity_info_ptr;
1510
0b0cfcf2 1511 struct sockaddr_in router;
1512 int router_len;
1513 u_short port = WCCP_PORT;
1514
1515 debug(80, 6) ("wccp2HereIam: Called\n");
1516
1517 if (wccp2_connected == 0) {
1518 debug(80, 1) ("wccp2HereIam: wccp2 socket closed. Shutting down WCCP2\n");
1519 return;
1520 }
1521
bef81ea5 1522 /* Wait if store dirs are rebuilding */
1523 if (StoreController::store_dirs_rebuilding && Config.Wccp2.rebuildwait) {
f67332d3 1524 eventAdd("wccp2HereIam", wccp2HereIam, NULL, 1.0, 1);
1525 return;
1526 }
1527
0b0cfcf2 1528 router_len = sizeof(router);
1529 memset(&router, '\0', router_len);
1530 router.sin_family = AF_INET;
1531 router.sin_port = htons(port);
1532
1533 /* for each router on each service send a packet */
1534 service_list_ptr = wccp2_service_list_head;
1535
1536 while (service_list_ptr != NULL) {
1537 debug(80, 5) ("wccp2HereIam: sending to service id %d\n", service_list_ptr->info.service_id);
1538
1539 for (router_list_ptr = &service_list_ptr->router_list_head; router_list_ptr->next != NULL; router_list_ptr = router_list_ptr->next) {
1540 router.sin_addr = router_list_ptr->router_sendto_address;
1541
1542 /* Set the cache id (ip) */
b7d249f9 1543
1544 switch (Config.Wccp2.assignment_method) {
1545
1546 case WCCP2_ASSIGNMENT_METHOD_HASH:
1547
1548 wccp2_identity_info_ptr = (struct wccp2_identity_info_t *) service_list_ptr->wccp2_identity_info_ptr;
1549 wccp2_identity_info_ptr->cache_identity.addr = router_list_ptr->local_ip;
1550 break;
1551
1552 case WCCP2_ASSIGNMENT_METHOD_MASK:
1553
1554 wccp2_mask_identity_info_ptr = (struct wccp2_mask_identity_info_t *) service_list_ptr->wccp2_identity_info_ptr;
1555 wccp2_mask_identity_info_ptr->cache_identity.addr = router_list_ptr->local_ip;
1556 break;
1557
1558 default:
1559 fatalf("Unknown Wccp2 assignment method\n");
1560 }
1561
0b0cfcf2 1562 /* Security update, if needed */
1563
1564 if (service_list_ptr->wccp2_security_type == WCCP2_MD5_SECURITY) {
1565 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);
1566 }
1567
1568 debug(80, 3) ("Sending HereIam packet size %d\n", (int) service_list_ptr->wccp_packet_size);
1569 /* Send the packet */
0b0cfcf2 1570
c1f55201 1571 if (wccp2_numrouters > 1) {
1572 comm_udp_sendto(theWccp2Connection,
1573 &router,
1574 router_len,
1575 &service_list_ptr->wccp_packet,
1576 service_list_ptr->wccp_packet_size);
1577 } else {
1578 send(theWccp2Connection,
1579 &service_list_ptr->wccp_packet,
1580 service_list_ptr->wccp_packet_size,
1581 0);
1582 }
0b0cfcf2 1583 }
1584
1585 service_list_ptr = service_list_ptr->next;
1586 }
1587
f67332d3 1588 eventAdd("wccp2HereIam", wccp2HereIam, NULL, 10.0, 1);
0b0cfcf2 1589}
1590
1591static void
1592wccp2AssignBuckets(void *voidnotused)
1593{
1594
1595 struct wccp2_service_list_t *service_list_ptr;
1596
1597 struct wccp2_router_list_t *router_list_ptr;
1598
1599 struct wccp2_cache_list_t *cache_list_ptr;
1600 char wccp_packet[WCCP_RESPONSE_SIZE];
b7d249f9 1601 short int offset, saved_offset, assignment_offset, alt_assignment_offset;
0b0cfcf2 1602
1603 struct sockaddr_in router;
1604 int router_len;
1605 int bucket_counter;
b7d249f9 1606 uint32_t service_flags;
0b0cfcf2 1607 u_short port = WCCP_PORT;
1608
1609 /* Packet segments */
1610
1611 struct wccp2_here_i_am_header_t *main_header;
1612
1613 struct wccp2_security_md5_t *security = NULL;
1614 /* service from service struct */
1615
1616 struct wccp2_item_header_t *assignment_header;
1617
b7d249f9 1618 struct wccp2_item_header_t *alt_assignment_type_header = NULL;
1619
0b0cfcf2 1620 struct assignment_key_t *assignment_key;
1621 /* number of routers */
1622
1623 struct wccp2_router_assign_element_t *router_assign;
1624 /* number of caches */
1625
1626 struct IN_ADDR *cache_address;
b7d249f9 1627 /* Alternative assignement mask/values */
1628 int num_maskval;
1629
1630 struct wccp2_mask_element_t *mask_element;
1631
1632 struct wccp2_value_element_t *value_element;
1633 int valuecounter, value;
0b0cfcf2 1634 char *buckets;
1635
b7d249f9 1636 assignment_offset = alt_assignment_offset = 0;
1637
0b0cfcf2 1638 router_len = sizeof(router);
1639 memset(&router, '\0', router_len);
1640 router.sin_family = AF_INET;
1641 router.sin_port = htons(port);
1642
1643 /* Start main header - fill in length later */
1644 offset = 0;
1645
1646 main_header = (struct wccp2_here_i_am_header_t *) &wccp_packet[offset];
1647 main_header->type = htonl(WCCP2_REDIRECT_ASSIGN);
1648 main_header->version = htons(WCCP2_VERSION);
1649
1650 debug(80, 2) ("Running wccp2AssignBuckets\n");
1651 service_list_ptr = wccp2_service_list_head;
1652
1653 while (service_list_ptr != NULL) {
1654 /* If we're not the lowest, we don't need to worry */
1655
1656 if (service_list_ptr->lowest_ip == 0) {
1657 /* XXX eww */
1658 service_list_ptr = service_list_ptr->next;
1659 continue;
1660 }
1661
1662 /* reset the offset */
1663
1664 offset = sizeof(struct wccp2_here_i_am_header_t);
1665
1666 /* build packet header from hereIam packet */
1667 /* Security info */
1668 /* XXX this should be made more generic! */
1669 /* XXX and I hate magic numbers! */
1670 switch (service_list_ptr->wccp2_security_type) {
1671
1672 case WCCP2_NO_SECURITY:
1673
1674 security = (struct wccp2_security_md5_t *) &wccp_packet[offset];
1675 memcpy(security, service_list_ptr->security_info, 8);
1676 offset += 8;
1677 break;
1678
1679 case WCCP2_MD5_SECURITY:
1680
1681 security = (struct wccp2_security_md5_t *) &wccp_packet[offset];
1682
1683 memcpy(security, service_list_ptr->security_info, sizeof(struct wccp2_security_md5_t));
1684
1685 offset += sizeof(struct wccp2_security_md5_t);
1686 break;
1687
1688 default:
1689 fatalf("Unknown Wccp2 security type\n");
1690 }
1691
1692 /* Service info */
1693
1694 memcpy(&wccp_packet[offset], service_list_ptr->service_info, sizeof(struct wccp2_service_info_t));
1695
1696 offset += sizeof(struct wccp2_service_info_t);
1697
1698 /* assignment header - fill in length later */
1699
1700 assignment_header = (struct wccp2_item_header_t *) &wccp_packet[offset];
1701
b7d249f9 1702 switch (Config.Wccp2.assignment_method) {
0b0cfcf2 1703
b7d249f9 1704 case WCCP2_ASSIGNMENT_METHOD_HASH:
1705 assignment_header->type = htons(WCCP2_REDIRECT_ASSIGNMENT);
1706
1707 offset += sizeof(struct wccp2_item_header_t);
1708 assignment_offset = offset;
1709 break;
1710
1711 case WCCP2_ASSIGNMENT_METHOD_MASK:
1712 assignment_header->type = htons(WCCP2_ALT_ASSIGNMENT);
1713
1714 offset += sizeof(struct wccp2_item_header_t);
1715 assignment_offset = offset;
1716
1717 /* The alternative assignment has an extra header, fill in length later */
1718
1719 alt_assignment_type_header = (struct wccp2_item_header_t *) &wccp_packet[offset];
1720 alt_assignment_type_header->type = htons(WCCP2_MASK_ASSIGNMENT);
1721
1722 offset += sizeof(struct wccp2_item_header_t);
1723 alt_assignment_offset = offset;
1724
1725 break;
1726
1727 default:
1728 fatalf("Unknown Wccp2 assignment method\n");
1729 }
0b0cfcf2 1730
1731 /* Assignment key - fill in master ip later */
1732
1733 assignment_key = (struct assignment_key_t *) &wccp_packet[offset];
1734
1735 assignment_key->master_number = htonl(++service_list_ptr->change_num);
1736
1737 offset += sizeof(struct assignment_key_t);
1738
1739 /* Number of routers */
1740 xmemcpy(&wccp_packet[offset], &service_list_ptr->num_routers, sizeof(service_list_ptr->num_routers));
1741
1742 offset += sizeof(service_list_ptr->num_routers);
1743
1744 for (router_list_ptr = &service_list_ptr->router_list_head; router_list_ptr->next != NULL; router_list_ptr = router_list_ptr->next) {
1745
1746 /* Add routers */
1747
1748 router_assign = (struct wccp2_router_assign_element_t *) &wccp_packet[offset];
1749 router_assign->router_address = router_list_ptr->info->router_address;
1750 router_assign->received_id = router_list_ptr->info->received_id;
1751 router_assign->change_number = htonl(router_list_ptr->member_change);
1752
1753 offset += sizeof(struct wccp2_router_assign_element_t);
1754 }
1755
1756 saved_offset = offset;
1757
1758 for (router_list_ptr = &service_list_ptr->router_list_head; router_list_ptr->next != NULL; router_list_ptr = router_list_ptr->next) {
b7d249f9 1759 unsigned long *weight = (unsigned long *)xcalloc(sizeof(*weight), ntohl(router_list_ptr->num_caches));
1760 unsigned long total_weight = 0;
1761 int num_caches = ntohl(router_list_ptr->num_caches);
f16fbc82 1762
0b0cfcf2 1763 offset = saved_offset;
1764
b7d249f9 1765 switch (Config.Wccp2.assignment_method) {
1766
1767 case WCCP2_ASSIGNMENT_METHOD_HASH:
1768 /* Number of caches */
1769 xmemcpy(&wccp_packet[offset], &router_list_ptr->num_caches, sizeof(router_list_ptr->num_caches));
1770 offset += sizeof(router_list_ptr->num_caches);
1771
1772 if (num_caches) {
1773 int cache;
1774
1775 for (cache = 0, cache_list_ptr = &router_list_ptr->cache_list_head; cache_list_ptr->next; cache_list_ptr = cache_list_ptr->next, cache++) {
1776 /* add caches */
0b0cfcf2 1777
b7d249f9 1778 cache_address = (struct IN_ADDR *) &wccp_packet[offset];
0b0cfcf2 1779
b7d249f9 1780 xmemcpy(cache_address, &cache_list_ptr->cache_ip, sizeof(struct IN_ADDR));
1781 total_weight += cache_list_ptr->weight << 12;
1782 weight[cache] = cache_list_ptr->weight << 12;
0b0cfcf2 1783
b7d249f9 1784 offset += sizeof(struct IN_ADDR);
1785 }
0b0cfcf2 1786 }
0b0cfcf2 1787
b7d249f9 1788 /* Add buckets */
1789 buckets = (char *) &wccp_packet[offset];
1790
1791 memset(buckets, '\0', WCCP_BUCKETS);
1792
1793 if (num_caches != 0) {
1794 if (total_weight == 0) {
1795 for (bucket_counter = 0; bucket_counter < WCCP_BUCKETS; bucket_counter++) {
1796 buckets[bucket_counter] = (char) (bucket_counter % num_caches);
1797 }
1798 } else {
1799 unsigned long *assigned = (unsigned long *)xcalloc(sizeof(*assigned), num_caches);
1800 unsigned long done = 0;
1801 int cache = -1;
1802 unsigned long per_bucket = total_weight / WCCP_BUCKETS;
1803
1804 for (bucket_counter = 0; bucket_counter < WCCP_BUCKETS; bucket_counter++) {
1805 int n;
1806 unsigned long step;
1807
1808 for (n = num_caches; n; n--) {
1809 cache++;
1810
1811 if (cache >= num_caches)
1812 cache = 0;
1813
1814 if (!weight[cache]) {
1815 n++;
1816 continue;
1817 }
1818
1819 if (assigned[cache] <= done)
1820 break;
1821 }
1822
1823 buckets[bucket_counter] = (char) cache;
1824 step = per_bucket * total_weight / weight[cache];
1825 assigned[cache] += step;
1826 done += per_bucket;
1827 }
1828
1829 safe_free(assigned);
1830 }
1831 }
0b0cfcf2 1832
b7d249f9 1833 offset += (WCCP_BUCKETS * sizeof(char));
1834 safe_free(weight);
1835 break;
0b0cfcf2 1836
b7d249f9 1837 case WCCP2_ASSIGNMENT_METHOD_MASK:
1838 num_maskval = htonl(1);
1839 xmemcpy(&wccp_packet[offset], &num_maskval, sizeof(int));
1840 offset += sizeof(int);
1841
1842 mask_element = (struct wccp2_mask_element_t *) &wccp_packet[offset];
1843 service_flags = ntohl(service_list_ptr->service_info->service_flags);
1844
1845 if ((service_flags & WCCP2_SERVICE_SRC_IP_HASH) || (service_flags & WCCP2_SERVICE_SRC_IP_ALT_HASH)) {
1846 mask_element->source_ip_mask = htonl(0x00001741);
1847 mask_element->dest_ip_mask = 0;
1848 mask_element->source_port_mask = 0;
1849 mask_element->dest_port_mask = 0;
1850 } 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)) {
1851 mask_element->source_ip_mask = 0;
1852 mask_element->dest_ip_mask = htonl(0x00001741);
1853 mask_element->source_port_mask = 0;
1854 mask_element->dest_port_mask = 0;
1855 } else if ((service_flags & WCCP2_SERVICE_SRC_PORT_HASH) || (service_flags & WCCP2_SERVICE_SRC_PORT_ALT_HASH)) {
1856 mask_element->source_ip_mask = 0;
1857 mask_element->dest_ip_mask = 0;
1858 mask_element->source_port_mask = htons(0x1741);
1859 mask_element->dest_port_mask = 0;
1860 } else if ((service_flags & WCCP2_SERVICE_DST_PORT_HASH) || (service_flags & WCCP2_SERVICE_DST_PORT_ALT_HASH)) {
1861 mask_element->source_ip_mask = 0;
1862 mask_element->dest_ip_mask = 0;
1863 mask_element->source_port_mask = 0;
1864 mask_element->dest_port_mask = htons(0x1741);
1865 } else {
1866 fatalf("Unknown service hash method\n");
1867 }
1868
1869 mask_element->number_values = htonl(64);
1870
1871 offset += sizeof(struct wccp2_mask_element_t);
1872
1873 cache_list_ptr = &router_list_ptr->cache_list_head;
1874 value = 0;
1875
1876 for (valuecounter = 0; valuecounter < 64; valuecounter++) {
1877
1878 value_element = (struct wccp2_value_element_t *) &wccp_packet[offset];
1879
25e26086 1880 /* Update the value according the the "correct" formula */
1881
1882 for (value++; (value & 0x1741) != value; value++) {
1883 assert(value <= 0x1741);
1884 }
1885
b7d249f9 1886 if ((service_flags & WCCP2_SERVICE_SRC_IP_HASH) || (service_flags & WCCP2_SERVICE_SRC_IP_ALT_HASH)) {
1887 value_element->source_ip_value = htonl(value);
1888 value_element->dest_ip_value = 0;
1889 value_element->source_port_value = 0;
1890 value_element->dest_port_value = 0;
1891 } 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)) {
1892 value_element->source_ip_value = 0;
1893 value_element->dest_ip_value = htonl(value);
1894 value_element->source_port_value = 0;
1895 value_element->dest_port_value = 0;
1896 } else if ((service_flags & WCCP2_SERVICE_SRC_PORT_HASH) || (service_flags & WCCP2_SERVICE_SRC_PORT_ALT_HASH)) {
1897 value_element->source_ip_value = 0;
1898 value_element->dest_ip_value = 0;
1899 value_element->source_port_value = htons(value);
1900 value_element->dest_port_value = 0;
1901 } else if ((service_flags & WCCP2_SERVICE_DST_PORT_HASH) || (service_flags & WCCP2_SERVICE_DST_PORT_ALT_HASH)) {
1902 value_element->source_ip_value = 0;
1903 value_element->dest_ip_value = 0;
1904 value_element->source_port_value = 0;
1905 value_element->dest_port_value = htons(value);
1906 } else {
1907 fatalf("Unknown service hash method\n");
1908 }
1909
1910 value_element->cache_ip = cache_list_ptr->cache_ip;
1911
1912 offset += sizeof(struct wccp2_value_element_t);
25e26086 1913 value++;
b7d249f9 1914
1915 /* Assign the next value to the next cache */
25e26086 1916
b7d249f9 1917 if ((cache_list_ptr->next) && (cache_list_ptr->next->next))
1918 cache_list_ptr = cache_list_ptr->next;
1919 else
1920 cache_list_ptr = &router_list_ptr->cache_list_head;
1921 }
0b0cfcf2 1922
b7d249f9 1923 /* Fill in length */
1924 alt_assignment_type_header->length = htons(offset - alt_assignment_offset);
1925
1926 break;
1927
1928 default:
1929 fatalf("Unknown Wccp2 assignment method\n");
1930 }
1931
1932 /* Fill in length */
0b0cfcf2 1933
b7d249f9 1934 assignment_header->length = htons(offset - assignment_offset);
0b0cfcf2 1935
1936 /* Fill in assignment key */
1937 assignment_key->master_ip = router_list_ptr->local_ip;
1938
1939 /* finish length */
1940
1941 main_header->length = htons(offset - sizeof(struct wccp2_here_i_am_header_t));
1942
1943 /* set the destination address */
1944 router.sin_addr = router_list_ptr->router_sendto_address;
1945
1946 /* Security update, if needed */
1947
1948 if (service_list_ptr->wccp2_security_type == WCCP2_MD5_SECURITY) {
1949 wccp2_update_md5_security(service_list_ptr->wccp_password, (char *) security, wccp_packet, offset);
1950 }
1951
1952 if (ntohl(router_list_ptr->num_caches)) {
1953 /* send packet */
c1f55201 1954
1955 if (wccp2_numrouters > 1) {
1956 comm_udp_sendto(theWccp2Connection,
1957 &router,
1958 router_len,
1959 &wccp_packet,
1960 offset);
1961 } else {
1962 send(theWccp2Connection,
1963 &wccp_packet,
1964 offset,
1965 0);
1966 }
0b0cfcf2 1967 }
1968 }
1969
1970 service_list_ptr = service_list_ptr->next;
1971 }
1972}
1973
1974
1975/*
1976 * Configuration option parsing code
1977 */
1978
1979/*
1980 * Format:
1981 *
1982 * wccp2_service {standard|dynamic} {id} (password=password)
1983 */
1984void
1985parse_wccp2_service(void *v)
1986{
1987 char *t;
1988 int service = 0;
1989 int service_id = 0;
1990 int security_type = WCCP2_NO_SECURITY;
1991 char wccp_password[WCCP2_PASSWORD_LEN + 1];
1992
1993 if (wccp2_connected == 1) {
1994 debug(80, 1) ("WCCPv2: Somehow reparsing the configuration "
1995 "without having shut down WCCP! Try reloading squid again.\n");
1996 return;
1997 }
1998
1999 /* Snarf the type */
2000 if ((t = strtok(NULL, w_space)) == NULL) {
2001 debug(80, 0) ("wccp2ParseServiceInfo: missing service info type (standard|dynamic)\n");
2002 self_destruct();
2003 }
2004
2005 if (strcmp(t, "standard") == 0) {
2006 service = WCCP2_SERVICE_STANDARD;
2007 } else if (strcmp(t, "dynamic") == 0) {
2008 service = WCCP2_SERVICE_DYNAMIC;
2009 } else {
2010 debug(80, 0) ("wccp2ParseServiceInfo: bad service info type (expected standard|dynamic, got %s)\n", t);
2011 self_destruct();
2012 }
2013
2014 /* Snarf the ID */
2015 service_id = GetInteger();
2016
2017 if (service_id < 0 || service_id > 255) {
2018 debug(80, 0) ("wccp2ParseServiceInfo: service info id %d is out of range (0..255)\n", service_id);
2019 self_destruct();
2020 }
2021
2022 memset(wccp_password, 0, sizeof(wccp_password));
2023 /* Handle password, if any */
2024
2025 if ((t = strtok(NULL, w_space)) != NULL) {
2026 if (strncmp(t, "password=", 9) == 0) {
2027 security_type = WCCP2_MD5_SECURITY;
2028 strncpy(wccp_password, t + 9, WCCP2_PASSWORD_LEN);
2029 }
2030 }
2031
2032 /* Create a placeholder service record */
2033 wccp2_add_service_list(service, service_id, 0, 0, 0, empty_portlist, security_type, wccp_password);
2034}
2035
2036void
2037dump_wccp2_service(StoreEntry * e, const char *label, void *v)
2038{
2039
2040 struct wccp2_service_list_t *srv;
2041 srv = wccp2_service_list_head;
2042
2043 while (srv != NULL) {
2044 debug(80, 3) ("dump_wccp2_service: id %d, type %d\n", srv->info.service_id, srv->info.service);
2045 storeAppendPrintf(e, "%s %s %d", label,
2046 (srv->info.service == WCCP2_SERVICE_DYNAMIC) ? "dynamic" : "standard",
2047 srv->info.service_id);
2048
2049 if (srv->wccp2_security_type == WCCP2_MD5_SECURITY) {
2050 storeAppendPrintf(e, " %s", srv->wccp_password);
2051 }
2052
2053 srv = srv->next;
2054 }
2055}
2056
2057void
2058free_wccp2_service(void *v)
2059{}
2060
2061int
2062check_null_wccp2_service(void *v)
2063{
2064 return !wccp2_service_list_head;
2065}
2066
2067/*
2068 * Format:
2069 *
2070 * wccp2_service_info {id} stuff..
2071 *
2072 * Where stuff is:
2073 *
2074 * + flags=flag,flag,flag..
2075 * + proto=protocol (tcp|udp)
2076 * + ports=port,port,port (up to a max of 8)
2077 * + priority=priority (0->255)
2078 *
2079 * The flags here are:
2080 * src_ip_hash, dst_ip_hash, source_port_hash, dst_port_hash, ports_defined,
2081 * ports_source, src_ip_alt_hash, dst_ip_alt_hash, src_port_alt_hash, dst_port_alt_hash
2082 */
2083static int
2084parse_wccp2_service_flags(char *flags)
2085{
2086 char *tmp, *tmp2;
2087 char *flag;
2088 int retflag = 0;
2089
2090 if (!flags) {
2091 return 0;
2092 }
2093
2094 tmp = xstrdup(flags);
2095 tmp2 = tmp;
2096
2097 flag = strsep(&tmp2, ",");
2098
2099 while (flag) {
2100 if (strcmp(flag, "src_ip_hash") == 0) {
2101 retflag |= WCCP2_SERVICE_SRC_IP_HASH;
2102 } else if (strcmp(flag, "dst_ip_hash") == 0) {
2103 retflag |= WCCP2_SERVICE_DST_IP_HASH;
2104 } else if (strcmp(flag, "source_port_hash") == 0) {
b7d249f9 2105 retflag |= WCCP2_SERVICE_SRC_PORT_HASH;
0b0cfcf2 2106 } else if (strcmp(flag, "dst_port_hash") == 0) {
2107 retflag |= WCCP2_SERVICE_DST_PORT_HASH;
2108 } else if (strcmp(flag, "ports_source") == 0) {
2109 retflag |= WCCP2_SERVICE_PORTS_SOURCE;
2110 } else if (strcmp(flag, "src_ip_alt_hash") == 0) {
2111 retflag |= WCCP2_SERVICE_SRC_IP_ALT_HASH;
2112 } else if (strcmp(flag, "dst_ip_alt_hash") == 0) {
2113 retflag |= WCCP2_SERVICE_DST_IP_ALT_HASH;
2114 } else if (strcmp(flag, "src_port_alt_hash") == 0) {
2115 retflag |= WCCP2_SERVICE_SRC_PORT_ALT_HASH;
2116 } else if (strcmp(flag, "dst_port_alt_hash") == 0) {
2117 retflag |= WCCP2_SERVICE_DST_PORT_ALT_HASH;
2118 } else {
2119 fatalf("Unknown wccp2 service flag: %s\n", flag);
2120 }
2121
2122 flag = strsep(&tmp2, ",");
2123 }
2124
2125 xfree(tmp);
2126 return retflag;
2127}
2128
2129static void
2130parse_wccp2_service_ports(char *options, int portlist[])
2131{
2132 int i = 0;
2133 int p;
2134 char *tmp, *tmp2, *port, *end;
2135
2136 if (!options) {
2137 return;
2138 }
2139
2140 tmp = xstrdup(options);
2141 tmp2 = tmp;
2142
2143 port = strsep(&tmp2, ",");
2144
2145 while (port && i < WCCP2_NUMPORTS) {
2146 p = strtol(port, &end, 0);
2147
2148 if (p < 1 || p > 65535) {
2149 fatalf("parse_wccp2_service_ports: port value '%s' isn't valid (1..65535)\n", port);
2150 }
2151
2152 portlist[i] = p;
2153 i++;
2154 port = strsep(&tmp2, ",");
2155 }
2156
2157 if (i == 8) {
2158 fatalf("parse_wccp2_service_ports: too many ports (maximum: 8) in list '%s'\n", options);
2159 }
2160
2161 xfree(tmp);
2162}
2163
2164void
2165parse_wccp2_service_info(void *v)
2166{
2167 char *t, *end;
2168 int service_id = 0;
2169 int flags = 0;
2170 int portlist[WCCP2_NUMPORTS];
2171 int protocol = -1; /* IPPROTO_TCP | IPPROTO_UDP */
2172
2173 struct wccp2_service_list_t *srv;
2174 int priority = -1;
2175
2176 if (wccp2_connected == 1) {
2177 debug(80, 1) ("WCCPv2: Somehow reparsing the configuration "
2178 "without having shut down WCCP! Try reloading squid again.\n");
2179 return;
2180 }
2181
2182 debug(80, 5) ("parse_wccp2_service_info: called\n");
a302ad3c 2183 memset(portlist, 0, sizeof(portlist));
0b0cfcf2 2184 /* First argument: id */
2185 service_id = GetInteger();
2186
2187 if (service_id < 0 || service_id > 255) {
2188 debug(80, 1) ("parse_wccp2_service_info: invalid service id %d (must be between 0 .. 255)\n", service_id);
2189 self_destruct();
2190 }
2191
2192 /* Next: find the (hopefully!) existing service */
2193 srv = wccp2_get_service_by_id(WCCP2_SERVICE_DYNAMIC, service_id);
2194
2195 if (srv == NULL) {
2196 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);
2197 }
2198
2199 /* Next: loop until we don't have any more tokens */
2200 while ((t = strtok(NULL, w_space)) != NULL) {
2201 if (strncmp(t, "flags=", 6) == 0) {
2202 /* XXX eww, string pointer math */
2203 flags = parse_wccp2_service_flags(t + 6);
2204 } else if (strncmp(t, "ports=", 6) == 0) {
2205 parse_wccp2_service_ports(t + 6, portlist);
2206 flags |= WCCP2_SERVICE_PORTS_DEFINED;
2207 } else if (strncmp(t, "protocol=tcp", 12) == 0) {
2208 protocol = IPPROTO_TCP;
2209 } else if (strncmp(t, "protocol=udp", 12) == 0) {
2210 protocol = IPPROTO_UDP;
2211 } else if (strncmp(t, "protocol=", 9) == 0) {
2212 fatalf("parse_wccp2_service_info: id %d: unknown protocol (%s) - must be tcp or udp!\n", service_id, t);
2213 } else if (strncmp(t, "priority=", 9) == 0) {
2214 priority = strtol(t + 9, &end, 0);
2215
2216 if (priority < 0 || priority > 255) {
2217 fatalf("parse_wccp2_service_info: id %d: %s out of range (0..255)!\n", service_id, t);
2218 }
2219 } else {
2220 fatalf("parse_wccp2_service_info: id %d: unknown option '%s'\n", service_id, t);
2221 }
2222 }
2223
2224 /* Check everything is set */
2225 if (priority == -1) {
2226 fatalf("parse_wccp2_service_info: service %d: no priority defined (valid: 0..255)!\n", service_id);
2227 }
2228
2229 if (protocol == -1) {
2230 fatalf("parse_wccp2_service_info: service %d: no protocol defined (valid: tcp or udp)!\n", service_id);
2231 }
2232
2233 if (!(flags & WCCP2_SERVICE_PORTS_DEFINED)) {
2234 fatalf("parse_wccp2_service_info: service %d: no ports defined!\n", service_id);
2235 }
2236
2237 /* rightio! now we can update */
2238 wccp2_update_service(srv, WCCP2_SERVICE_DYNAMIC, service_id, priority,
2239 protocol, flags, portlist);
2240
2241 /* Done! */
2242}
2243
2244void
2245dump_wccp2_service_info(StoreEntry * e, const char *label, void *v)
2246{
2247 char comma;
2248
2249 struct wccp2_service_list_t *srv;
2250 int flags;
2251 srv = wccp2_service_list_head;
2252
2253 while (srv != NULL) {
2254 debug(80, 3) ("dump_wccp2_service_info: id %d (type %d)\n", srv->info.service_id, srv->info.service);
2255
2256 /* We don't need to spit out information for standard services */
2257
2258 if (srv->info.service == WCCP2_SERVICE_STANDARD) {
2259 debug(80, 3) ("dump_wccp2_service_info: id %d: standard service, not dumping info\n", srv->info.service_id);
2260 /* XXX eww */
2261 srv = srv->next;
2262 continue;
2263 }
2264
2265 storeAppendPrintf(e, "%s %d", label, srv->info.service_id);
2266
2267 /* priority */
2268 storeAppendPrintf(e, " priority=%d", srv->info.service_priority);
2269
2270 /* flags */
2271 flags = ntohl(srv->info.service_flags);
2272
2273 if (flags != 0) {
2274 comma = 0;
2275 storeAppendPrintf(e, " flags=");
2276
2277 if (flags & WCCP2_SERVICE_SRC_IP_HASH) {
2278 storeAppendPrintf(e, "%ssrc_ip_hash", comma ? "," : "");
2279 comma = 1;
2280 }
2281
2282 if (flags & WCCP2_SERVICE_DST_IP_HASH) {
2283 storeAppendPrintf(e, "%sdst_ip_hash", comma ? "," : "");
2284 comma = 1;
2285 }
2286
b7d249f9 2287 if (flags & WCCP2_SERVICE_SRC_PORT_HASH) {
0b0cfcf2 2288 storeAppendPrintf(e, "%ssource_port_hash", comma ? "," : "");
2289 comma = 1;
2290 }
2291
2292 if (flags & WCCP2_SERVICE_DST_PORT_HASH) {
2293 storeAppendPrintf(e, "%sdst_port_hash", comma ? "," : "");
2294 comma = 1;
2295 }
2296
2297 if (flags & WCCP2_SERVICE_PORTS_DEFINED) {
2298 storeAppendPrintf(e, "%sports_defined", comma ? "," : "");
2299 comma = 1;
2300 }
2301
2302 if (flags & WCCP2_SERVICE_PORTS_SOURCE) {
2303 storeAppendPrintf(e, "%sports_source", comma ? "," : "");
2304 comma = 1;
2305 }
2306
2307 if (flags & WCCP2_SERVICE_SRC_IP_ALT_HASH) {
2308 storeAppendPrintf(e, "%ssrc_ip_alt_hash", comma ? "," : "");
2309 comma = 1;
2310 }
2311
2312 if (flags & WCCP2_SERVICE_DST_IP_ALT_HASH) {
2313 storeAppendPrintf(e, "%ssrc_ip_alt_hash", comma ? "," : "");
2314 comma = 1;
2315 }
2316
2317 if (flags & WCCP2_SERVICE_SRC_PORT_ALT_HASH) {
2318 storeAppendPrintf(e, "%ssrc_port_alt_hash", comma ? "," : "");
2319 comma = 1;
2320 }
2321
2322 if (flags & WCCP2_SERVICE_DST_PORT_ALT_HASH) {
2323 storeAppendPrintf(e, "%sdst_port_alt_hash", comma ? "," : "");
2324 comma = 1;
2325 }
2326 }
2327
2328 /* ports */
2329 comma = 0;
2330
2331 if (srv->info.port0 != 0) {
2332 storeAppendPrintf(e, "%s%d", comma ? "," : " ports=", ntohs(srv->info.port0));
2333 comma = 1;
2334 }
2335
2336 if (srv->info.port1 != 0) {
2337 storeAppendPrintf(e, "%s%d", comma ? "," : "ports=", ntohs(srv->info.port1));
2338 comma = 1;
2339 }
2340
2341 if (srv->info.port2 != 0) {
2342 storeAppendPrintf(e, "%s%d", comma ? "," : "ports=", ntohs(srv->info.port2));
2343 comma = 1;
2344 }
2345
2346 if (srv->info.port3 != 0) {
2347 storeAppendPrintf(e, "%s%d", comma ? "," : "ports=", ntohs(srv->info.port3));
2348 comma = 1;
2349 }
2350
2351 if (srv->info.port4 != 0) {
2352 storeAppendPrintf(e, "%s%d", comma ? "," : "ports=", ntohs(srv->info.port4));
2353 comma = 1;
2354 }
2355
2356 if (srv->info.port5 != 0) {
2357 storeAppendPrintf(e, "%s%d", comma ? "," : "ports=", ntohs(srv->info.port5));
2358 comma = 1;
2359 }
2360
2361 if (srv->info.port6 != 0) {
2362 storeAppendPrintf(e, "%s%d", comma ? "," : "ports=", ntohs(srv->info.port6));
2363 comma = 1;
2364 }
2365
2366 if (srv->info.port7 != 0) {
2367 storeAppendPrintf(e, "%s%d", comma ? "," : "ports=", ntohs(srv->info.port7));
2368 comma = 1;
2369 }
2370
2371 /* protocol */
2372 storeAppendPrintf(e, " protocol=%s", (srv->info.service_protocol == IPPROTO_TCP) ? "tcp" : "udp");
2373
2374 storeAppendPrintf(e, "\n");
2375
2376 srv = srv->next;
2377 }
2378}
2379
2380void
2381free_wccp2_service_info(void *v)
2382{}
2383
2384#endif /* USE_WCCPv2 */