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