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