WCCPv2 для squid на FreeBSD (eng) (eccp squid transparent proxy freebsd patch)
Ключевые слова: eccp, squid, transparent, proxy, freebsd, patch, (найти похожие документы)
From: Sinyuk Roman <roman@univ.kiev.ua.>
Date: Mon, 20 Jan 2005 18:21:07 +0000 (UTC)
Subject: WCCPv2 для squid на FreeBSD (eng)
Оригинал: http://www.univ.kiev.ua/~roman/wccpv2/
WCCPv2 for squid on FreeBSD howto
Requirements:
* Tested on FreeBSD 4.8R and FreeBSD-Stable.
* Squid-2.5.STABLE4
* Cisco IOS with wccp support (ip plus or enterprise plus)
Note: WCCPv1 and WCCPv2 have different encapsulation formats, and are
not compatible. GRE frames with WCCPv2 encapsulated packets has extra
4 bytes in GRE header, and kernel code modification required.
* Step 1. Modify /usr/src/sys/net/if_gre.h. Add in to struct gre_h 4
bytes field:
struct gre_h {
u_int16_t flags; /* GRE flags */
u_int16_t ptype; /* protocol type of payload typically
Ether protocol type*/
u_int32_t xxx; /* Add it for WCCPv2 support */
...
* Step 2. Add "pseudo-device gre" to kernel configuration file,
recompile kernel and reboot computer
# cd /usr/src/sys/i386/conf
# vi KERNEL_CONF
# config -r KERNEL_CONF
# cd ../../compile/KERNEL_CONF
# make depend
# make
# make install
# shutdown -r now
* Step 3.a For installing squid from sources apply wccpv2 patch
(modified version of Visolve patch) to squid sources before
building:
# fetch http://www.univ.kiev.ua/~roman/wccpv2/wccpv2.patch
# tar -xzvf squid-2.5.STABLE4.tar.gz
# cd squid-2.5.STABLE4
# patch -p1 < ../wccpv2.patch
# ./configure --enable-wccpv2 ...
# make
# make install
* Step 3.b For building squid from FreeBSD port (autoconf-2.* and
automake-1.5* must be installed before):
# fetch http://www.univ.kiev.ua/~roman/wccpv2/squid-2.5-wccpv2.tar.gz
# tar -xzvf squid-2.5-wccpv2.tar.gz
# cd squid-2.5-wccpv2
If you want to install squid with other then default prefix define PREFIX va
riable:
# export PREFIX=/usr/local/squid
Add extra CONFIGURE_ARGS in Makefile.local (for example delay-pools, cache-d
igests, ...)
# vi Makefile.local
Build and install port:
# make
# make install
* Step 5. Create GRE tunnel to your Cisco router
# ifconfig gre0 create
# ifconfig gre0 link0 tunnel squid_host_IP router_IP up
where:
router_IP is IP address of routers physical interface (not
loopback interface)
* Step 7. Configure Cisco router
# configure terminal
# ip wccp 97 password abc123
# interface loopback 0
# ip address 192.168.0.1 255.255.255.255
# interface Serial 0
# ip wccp 97 redirect out
# end
where:
97 is wccp2_service_id parameter and abc123 is wccp2_password,
both defined in squid.conf
Interface loopback IP used by WCCPv2 as router-id.
Interface Serial 0 is external interface.
* Step 8. Configure IPFW
# ipfw add fwd 127.0.0.1,3128 ip from any to any via gre0 in
# ipfw add permit ip from any to any
* Step 9. Configure squid. Edit squid.conf file and set:
wccp2_router 192.168.0.1
wccp2_password abc123
wccp2_service_id 97
wccp2_redirect_port1 80
wccp2_redirect_port2 81
wccp2_redirect_port3 8000
wccp2_redirect_port4 8080
wccp2_redirect_port5 3128
wccp2_redirect_port6 8900
wccp2_redirect_port7 0
wccp2_redirect_port8 0
httpd_accel_host virtual
httpd_accel_port 0
httpd_accel_with_proxy on
httpd_accel_uses_host_header on
* Step 10. Start squid.
wccpv2.patch
diff -Nur squid-2.5.STABLE4/acconfig.h squid-2.5.STABLE4_wccpv2/acconfig.h
--- squid-2.5.STABLE4/acconfig.h Mon Jul 1 11:55:11 2002
+++ squid-2.5.STABLE4_wccpv2/acconfig.h Sun Jan 25 04:31:20 2004
@@ -112,9 +112,14 @@
#undef SQUID_SNMP
/*
- * Define to enable WCCP
+ * Define to enable WCCPv1
*/
#define USE_WCCP 1
+
+/*
+ * Define to enable WCCP V2
+ */
+#undef USE_WCCPv2
/*
* Squid frequently calls gettimeofday() for accurate timestamping.
diff -Nur squid-2.5.STABLE4/configure squid-2.5.STABLE4_wccpv2/configure
--- squid-2.5.STABLE4/configure Mon Sep 15 03:37:04 2003
+++ squid-2.5.STABLE4_wccpv2/configure Sun Jan 25 04:31:20 2004
@@ -70,7 +70,9 @@
ac_help="$ac_help
--enable-referer-log Enable logging of Referer header"
ac_help="$ac_help
- --disable-wccp Disable Web Cache Coordination Protocol"
+ --disable-wccp Disable Web Cache Coordination V1 Protocol"
+ac_help="$ac_help
+ --enable-wccpv2 Enable Web Cache Coordination V2 Protocol"
ac_help="$ac_help
--enable-kill-parent-hack
Kill parent on shutdown"
@@ -2133,7 +2135,7 @@
if test "${enable_wccp+set}" = set; then
enableval="$enable_wccp"
if test "$enableval" = "no" ; then
- echo "Web Cache Coordination Protocol disabled"
+ echo "Web Cache Coordination V1 Protocol disabled"
cat >> confdefs.h <<\EOF
#define USE_WCCP 0
EOF
@@ -2161,6 +2163,35 @@
fi
+if false; then
+ USE_WCCPv2_TRUE=
+ USE_WCCPv2_FALSE='#'
+else
+ USE_WCCPv2_TRUE='#'
+ USE_WCCPv2_FALSE=
+fi
+# Check whether --enable-wccpv2 or --disable-wccpv2 was given.
+if test "${enable_wccpv2+set}" = set; then
+ enableval="$enable_wccpv2"
+ if test "$enableval" = "yes"; then
+ echo "Web Cache Coordination V2 Protocol Enabled"
+ cat >> confdefs.h <<\EOF
+#define USE_WCCPv2 1
+EOF
+
+
+
+if true; then
+ USE_WCCPv2_TRUE=
+ USE_WCCPv2_FALSE='#'
+else
+ USE_WCCPv2_TRUE='#'
+ USE_WCCPv2_FALSE=
+fi
+ fi
+
+fi
+
@@ -8594,6 +8625,8 @@
s%@ENABLE_PINGER_FALSE@%$ENABLE_PINGER_FALSE%g
s%@USE_DELAY_POOLS_TRUE@%$USE_DELAY_POOLS_TRUE%g
s%@USE_DELAY_POOLS_FALSE@%$USE_DELAY_POOLS_FALSE%g
+s%@USE_WCCPv2_TRUE@%$USE_WCCPv2_TRUE%g
+s%@USE_WCCPv2_FALSE@%$USE_WCCPv2_FALSE%g
s%@USE_SNMP_TRUE@%$USE_SNMP_TRUE%g
s%@USE_SNMP_FALSE@%$USE_SNMP_FALSE%g
s%@SNMPLIB@%$SNMPLIB%g
diff -Nur squid-2.5.STABLE4/configure.in squid-2.5.STABLE4_wccpv2/configure.in
--- squid-2.5.STABLE4/configure.in Mon Sep 15 03:37:04 2003
+++ squid-2.5.STABLE4_wccpv2/configure.in Sun Jan 25 04:31:20 2004
@@ -459,15 +459,26 @@
fi
])
-AC_ARG_ENABLE(wccp,
-[ --disable-wccp Disable Web Cache Coordination Protocol],
+AC_ARG_ENABLE(wccp,
+[ --disable-wccp Disable Web Cache Coordination V1 Protocol],
[ if test "$enableval" = "no" ; then
- echo "Web Cache Coordination Protocol disabled"
+ echo "Web Cache Coordination V1 Protocol disabled"
AC_DEFINE(USE_WCCP, 0)
else
AC_DEFINE(USE_WCCP, 1)
fi
-])
+])
+
+AM_CONDITIONAL(USE_WCCPv2, false)
+AC_ARG_ENABLE(wccpv2,
+[ --enable-wccpv2 Enable Web Cache Coordination V2 Protocol],
+[ if test "$enableval" = "yes" ; then
+ echo "Web Cache Coordination V2 Protocol enabled"
+ AC_DEFINE(USE_WCCPv2, 1)
+ AM_CONDITIONAL(USE_WCCPv2, true)
+ fi
+])
+
AC_ARG_ENABLE(kill-parent-hack,
[ --enable-kill-parent-hack
diff -Nur squid-2.5.STABLE4/include/autoconf.h.in squid-2.5.STABLE4_wccpv2/include/autoconf.h.in
--- squid-2.5.STABLE4/include/autoconf.h.in Sat Jan 18 03:46:33 2003
+++ squid-2.5.STABLE4_wccpv2/include/autoconf.h.in Sun Jan 25 04:31:20 2004
@@ -149,9 +149,14 @@
#undef SQUID_SNMP
/*
- * Define to enable WCCP
+ * Define to enable WCCP V1
*/
#define USE_WCCP 1
+
+/*
+ * Define to enable WCCP V2
+ */
+#undef USE_WCCPv2
/*
* Define this to include code which lets you specify access control
diff -Nur squid-2.5.STABLE4/src/Makefile.in squid-2.5.STABLE4_wccpv2/src/Makefile.in
--- squid-2.5.STABLE4/src/Makefile.in Wed Feb 12 04:03:14 2003
+++ squid-2.5.STABLE4_wccpv2/src/Makefile.in Sun Jan 25 04:31:20 2004
@@ -131,6 +131,9 @@
@USE_DELAY_POOLS_TRUE@DELAY_POOL_SOURCE = delay_pools.c
@USE_DELAY_POOLS_FALSE@DELAY_POOL_SOURCE =
+@USE_WCCPv2_TRUE@WCCPv2_SOURCE = wccpv2.c
+@USE_WCCPv2_FALSE@WCCPv2_SOURCE =
+
@ENABLE_HTCP_TRUE@HTCPSOURCE = htcp.c
@MAKE_LEAKFINDER_TRUE@LEAKFINDERSOURCE = leakfinder.c
@@ -196,6 +199,7 @@
unlinkd.c \
ssl_support.c \
ssl_support.h \
+ wccpv2.c \
win32.c
@@ -297,6 +301,7 @@
useragent.c \
wais.c \
wccp.c \
+ $(WCCPv2_SOURCE) \
whois.c \
$(WIN32SOURCE)
@@ -471,8 +476,10 @@
@ENABLE_SSL_TRUE@am__objects_8 = ssl_support.$(OBJEXT)
@ENABLE_UNLINKD_TRUE@am__objects_9 = unlinkd.$(OBJEXT)
@ENABLE_UNLINKD_FALSE@am__objects_9 =
-@ENABLE_WIN32SPECIFIC_FALSE@am__objects_10 =
-@ENABLE_WIN32SPECIFIC_TRUE@am__objects_10 = win32.$(OBJEXT)
+@USE_WCCPv2_FALSE@am__objects_10 =
+@USE_WCCPv2_TRUE@am__objects_10 = wccpv2.$(OBJEXT)
+@ENABLE_WIN32SPECIFIC_FALSE@am__objects_11 =
+@ENABLE_WIN32SPECIFIC_TRUE@am__objects_11 = win32.$(OBJEXT)
am_squid_OBJECTS = access_log.$(OBJEXT) acl.$(OBJEXT) asn.$(OBJEXT) \
authenticate.$(OBJEXT) cache_cf.$(OBJEXT) CacheDigest.$(OBJEXT) \
cache_manager.$(OBJEXT) carp.$(OBJEXT) cbdata.$(OBJEXT) \
@@ -505,7 +512,7 @@
store_swapmeta.$(OBJEXT) store_swapout.$(OBJEXT) \
tools.$(OBJEXT) $(am__objects_9) url.$(OBJEXT) urn.$(OBJEXT) \
useragent.$(OBJEXT) wais.$(OBJEXT) wccp.$(OBJEXT) \
- whois.$(OBJEXT) $(am__objects_10)
+ $(am__objects_10) whois.$(OBJEXT) $(am__objects_11)
nodist_squid_OBJECTS = repl_modules.$(OBJEXT) auth_modules.$(OBJEXT) \
store_modules.$(OBJEXT) globals.$(OBJEXT) \
string_arrays.$(OBJEXT)
@@ -580,7 +587,7 @@
@AMDEP_TRUE@ $(DEPDIR)/unlinkd.Po $(DEPDIR)/url.Po \
@AMDEP_TRUE@ $(DEPDIR)/urn.Po $(DEPDIR)/useragent.Po \
@AMDEP_TRUE@ $(DEPDIR)/wais.Po $(DEPDIR)/wccp.Po \
-@AMDEP_TRUE@ $(DEPDIR)/whois.Po $(DEPDIR)/win32.Po
+@AMDEP_TRUE@ $(DEPDIR)/wccpv2.Po $(DEPDIR)/whois.Po $(DEPDIR)/win32.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
@@ -815,6 +822,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/useragent.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/wais.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/wccp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/wccpv2.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/whois.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/win32.Po@am__quote@
diff -Nur squid-2.5.STABLE4/src/cf.data.pre squid-2.5.STABLE4_wccpv2/src/cf.data.pre
--- squid-2.5.STABLE4/src/cf.data.pre Tue Sep 2 10:49:32 2003
+++ squid-2.5.STABLE4_wccpv2/src/cf.data.pre Sun Jan 25 04:32:18 2004
@@ -3194,17 +3194,125 @@
LOC: Config.Wccp.router
DEFAULT: 0.0.0.0
IFDEF: USE_WCCP
+DOC_NONE
+NAME: wccp2_router
+TYPE: address
+LOC: Config.Wccp2.router
+DEFAULT: 0.0.0.0
+IFDEF: USE_WCCPv2
DOC_START
Use this option to define your WCCP ``home'' router for
Squid. Setting the 'wccp_router' to 0.0.0.0 (the default)
disables WCCP.
DOC_END
+NAME: wccp2_password
+TYPE: string
+LOC: Config.Wccp2.password
+DEFAULT: xxx123
+IFDEF: USE_WCCPv2
+DOC_START
+ Password for WCCP service. Password is mandatory, first eight
+ characters are significant.
+DOC_END
+
+NAME: wccp2_service_id
+TYPE: int
+LOC: Config.Wccp2.service_id
+DEFAULT: 97
+IFDEF: USE_WCCPv2
+DOC_START
+ WCCP service group number. Numbers from 90 to 97 are user
+ configurable. Set the same service group number on router.
+ For example, if service group number is 97 and password is
+ xxx123, make global and interface router settings:
+ "ip wccp 97 password xxx123", "ip wccp 97 redirect out|in"
+DOC_END
+
+NAME: wccp2_redirect_port1
+TYPE: ushort
+LOC: Config.Wccp2.redirect_port1
+DEFAULT: 80
+IFDEF: USE_WCCPv2
+DOC_START
+ First redirected TCP port number. Single service group allows
+ up to 8 ports redirect. Set to zero for unused ports.
+DOC_END
+
+NAME: wccp2_redirect_port2
+TYPE: ushort
+LOC: Config.Wccp2.redirect_port2
+DEFAULT: 8080
+IFDEF: USE_WCCPv2
+DOC_START
+ Second redirected port number.
+DOC_END
+
+NAME: wccp2_redirect_port3
+TYPE: ushort
+LOC: Config.Wccp2.redirect_port3
+DEFAULT: 8000
+IFDEF: USE_WCCPv2
+DOC_START
+ Thirs redirected port number.
+DOC_END
+
+NAME: wccp2_redirect_port4
+TYPE: ushort
+LOC: Config.Wccp2.redirect_port4
+DEFAULT: 0
+IFDEF: USE_WCCPv2
+DOC_START
+ Fours redirected port number. (unused by default)
+DOC_END
+
+NAME: wccp2_redirect_port5
+TYPE: ushort
+LOC: Config.Wccp2.redirect_port5
+DEFAULT: 0
+IFDEF: USE_WCCPv2
+DOC_START
+ Fifth redirected port number. (unused by default)
+DOC_END
+
+NAME: wccp2_redirect_port6
+TYPE: ushort
+LOC: Config.Wccp2.redirect_port6
+DEFAULT: 0
+IFDEF: USE_WCCPv2
+DOC_START
+ Sixth redirected port number. (unused by default)
+DOC_END
+
+NAME: wccp2_redirect_port7
+TYPE: ushort
+LOC: Config.Wccp2.redirect_port7
+DEFAULT: 0
+IFDEF: USE_WCCPv2
+DOC_START
+ Seventh redirected port number. (unused by default)
+DOC_END
+
+NAME: wccp2_redirect_port8
+TYPE: ushort
+LOC: Config.Wccp2.redirect_port8
+DEFAULT: 0
+IFDEF: USE_WCCPv2
+DOC_START
+ Eighth redirected port number. (unused by default)
+DOC_END
+
NAME: wccp_version
TYPE: int
LOC: Config.Wccp.version
DEFAULT: 4
IFDEF: USE_WCCP
+DOC_NONE
+NAME: wccp2_version
+TYPE: int
+LOC: Config.Wccp2.version
+DEFAULT: 4
+IFDEF: USE_WCCPv2
DOC_START
According to some users, Cisco IOS 11.2 only supports WCCP
version 3. If you're using that version of IOS, change
@@ -3222,6 +3330,18 @@
LOC: Config.Wccp.outgoing
DEFAULT: 255.255.255.255
IFDEF: USE_WCCP
+DOC_NONE
+NAME: wccp2_incoming_address
+TYPE: address
+LOC: Config.Wccp2.incoming
+DEFAULT: 0.0.0.0
+IFDEF: USE_WCCPv2
+DOC_NONE
+NAME: wccp2_outgoing_address
+TYPE: address
+LOC: Config.Wccp2.outgoing
+DEFAULT: 255.255.255.255
+IFDEF: USE_WCCPv2
DOC_START
wccp_incoming_address Use this option if you require WCCP
messages to be received on only one
diff -Nur squid-2.5.STABLE4/src/cf_gen_defines squid-2.5.STABLE4_wccpv2/src/cf_gen_defines
--- squid-2.5.STABLE4/src/cf_gen_defines Mon Dec 3 10:01:53 2001
+++ squid-2.5.STABLE4_wccpv2/src/cf_gen_defines Sun Jan 25 04:31:20 2004
@@ -18,6 +18,7 @@
define["USE_UNLINKD"]="--enable-unlinkd"
define["USE_USERAGENT_LOG"]="--enable-useragent-log"
define["USE_WCCP"]="--enable-wccp"
+ define["USE_WCCPv2"]="--enable-wccpv2"
}
/^IFDEF:/ {
if (define[$2] != "")
diff -Nur squid-2.5.STABLE4/src/main.c squid-2.5.STABLE4_wccpv2/src/main.c
--- squid-2.5.STABLE4/src/main.c Mon Jun 9 02:28:46 2003
+++ squid-2.5.STABLE4_wccpv2/src/main.c Sun Jan 25 04:31:20 2004
@@ -297,6 +297,9 @@
#if USE_WCCP
wccpConnectionOpen();
#endif
+#if USE_WCCPv2
+ wccp2ConnectionOpen();
+#endif
clientdbInit();
icmpOpen();
netdbInit();
@@ -323,6 +326,9 @@
#if USE_WCCP
wccpConnectionShutdown();
#endif
+#if USE_WCCPv2
+ wccp2ConnectionShutdown();
+#endif
asnFreeMemory();
}
@@ -343,6 +349,9 @@
#if USE_WCCP
wccpConnectionClose();
#endif
+#if USE_WCCPv2
+ wccp2ConnectionClose();
+#endif
#if USE_DNSSERVERS
dnsShutdown();
#else
@@ -381,6 +390,9 @@
#if USE_WCCP
wccpInit();
#endif
+#if USE_WCCPv2
+ wccp2Init();
+#endif
serverConnectionsOpen();
if (theOutIcpConnection >= 0) {
if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
@@ -544,6 +556,9 @@
#if USE_WCCP
wccpInit();
#endif
+#if USE_WCCPv2
+ wccp2Init();
+#endif
serverConnectionsOpen();
if (theOutIcpConnection >= 0) {
if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
@@ -969,6 +984,9 @@
#endif
#if USE_WCCP
wccpConnectionClose();
+#endif
+#if USE_WCCPv2
+ wccp2ConnectionClose();
#endif
releaseServerSockets();
commCloseAllSockets();
diff -Nur squid-2.5.STABLE4/src/protos.h squid-2.5.STABLE4_wccpv2/src/protos.h
--- squid-2.5.STABLE4/src/protos.h Mon Aug 11 00:04:47 2003
+++ squid-2.5.STABLE4_wccpv2/src/protos.h Sun Jan 25 04:31:20 2004
@@ -570,6 +570,13 @@
extern void wccpConnectionClose(void);
#endif /* USE_WCCP */
+#if USE_WCCPv2
+extern void wccp2Init(void);
+extern void wccp2ConnectionOpen(void);
+extern void wccp2ConnectionShutdown(void);
+extern void wccp2ConnectionClose(void);
+#endif /* USE_WCCPv2 */
+
extern void icpHandleIcpV3(int, struct sockaddr_in, char *, int);
extern int icpCheckUdpHit(StoreEntry *, request_t * request);
extern void icpConnectionsOpen(void);
diff -Nur squid-2.5.STABLE4/src/structs.h squid-2.5.STABLE4_wccpv2/src/structs.h
--- squid-2.5.STABLE4/src/structs.h Fri Sep 12 23:30:16 2003
+++ squid-2.5.STABLE4_wccpv2/src/structs.h Sun Jan 25 04:31:39 2004
@@ -450,6 +450,24 @@
int version;
} Wccp;
#endif
+#if USE_WCCPv2
+ struct {
+ struct in_addr router;
+ struct in_addr incoming;
+ struct in_addr outgoing;
+ int version;
+ char *password;
+ int service_id;
+ uint16_t redirect_port1;
+ uint16_t redirect_port2;
+ uint16_t redirect_port3;
+ uint16_t redirect_port4;
+ uint16_t redirect_port5;
+ uint16_t redirect_port6;
+ uint16_t redirect_port7;
+ uint16_t redirect_port8;
+ } Wccp2;
+#endif
char *as_whois_server;
struct {
char *log;
diff -Nur squid-2.5.STABLE4/src/wccpv2.c squid-2.5.STABLE4_wccpv2/src/wccpv2.c
--- squid-2.5.STABLE4/src/wccpv2.c Thu Jan 1 03:00:00 1970
+++ squid-2.5.STABLE4_wccpv2/src/wccpv2.c Sun Jan 25 04:32:03 2004
@@ -0,0 +1,578 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 80 WCCP Support
+ * AUTHOR: Glenn Chisholm
+ *
+ * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from the
+ * Internet community. Development is led by Duane Wessels of the
+ * National Laboratory for Applied Network Research and funded by the
+ * National Science Foundation. Squid is Copyrighted (C) 1998 by
+ * Duane Wessels and the University of California San Diego. Please
+ * see the COPYRIGHT file for full details. Squid incorporates
+ * software developed and/or copyrighted by other sources. Please see
+ * the CREDITS file for full details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+#include "squid.h"
+#include <netdb.h>
+
+#include <md5.h>
+MD5_CTX context;
+
+#if USE_WCCPv2
+
+char wccp_password[8];
+
+#define WCCP_PORT 2048
+#define WCCP_VERSION 4
+#define WCCP_REVISION 0
+#define WCCP_RESPONSE_SIZE 12448
+#define WCCP_ACTIVE_CACHES 32
+#define WCCP_HASH_SIZE 32
+#define WCCP_BUCKETS 256
+
+#define WCCP_HERE_I_AM 7
+#define WCCP_I_SEE_YOU 8
+#define WCCP_ASSIGN_BUCKET 9
+
+static int theInWccpConnection = -1;
+static int theOutWccpConnection = -1;
+static int change;
+static struct in_addr local_ip;
+
+static PF wccp2HandleUdp;
+static int wccp2LowestIP(void);
+static EVH wccp2HereIam;
+static EVH wccp2AssignBuckets;
+
+/* KDW WCCP V2 */
+#define WCCP2_HERE_I_AM 10
+#define WCCP2_I_SEE_YOU 11
+#define WCCP2_REDIRECT_ASSIGN 12
+#define WCCP2_REMOVAL_QUERY 13
+#define WCCP2_VERSION 0x200
+
+#define WCCP2_SECURITY_INFO 0
+#define WCCP2_NO_SECURITY 0
+#define WCCP2_MD5_SECURITY 1
+
+#define WCCP2_SERVICE_INFO 1
+#define WCCP2_SERVICE_STANDARD 0
+#define WCCP2_SERVICE_DYNAMIC 1
+#define WCCP2_SERVICE_ID_HTTP 0x00
+
+#define WCCP2_ROUTER_ID_INFO 2
+
+#define WCCP2_WC_ID_INFO 3
+
+#define WCCP2_RTR_VIEW_INFO 4
+
+#define WCCP2_WC_VIEW_INFO 5
+
+#define WCCP2_REDIRECT_ASSIGNMENT 6
+
+#define WCCP2_QUERY_INFO 7
+
+#define WCCP2_CAPABILTIY_INFO 8
+
+struct wccp2_here_i_am_t {
+ uint32_t type;
+ uint16_t version;
+ uint16_t length;
+ uint16_t security_type;
+ uint16_t security_length;
+ uint32_t security_option;
+ unsigned char security_implementation[16];
+ uint16_t service_type;
+ uint16_t service_length;
+ uint8_t service;
+ uint8_t serviceid;
+ uint8_t priority;
+ uint8_t protocol;
+ uint32_t service_flags;
+ uint16_t ports[8];
+ uint16_t cache_identity_type;
+ uint16_t cache_identity_length;
+ struct in_addr cache_identity_addr;
+ char cache_identity_filler[40];
+ uint16_t cache_view_type;
+ uint16_t cache_view_length;
+ uint32_t cache_view_version;
+ uint32_t cache_view_num_routers;
+ struct in_addr cache_view_rtr1_addr;
+ uint32_t cache_view_rtr1_receive_id;
+ uint32_t cache_view_num_caches;
+ int id;
+};
+
+static struct wccp2_here_i_am_t wccp2_here_i_am;
+
+struct wccp2_i_see_you_t {
+ uint32_t type;
+ uint16_t version;
+ uint16_t length;
+ char data[WCCP_RESPONSE_SIZE];
+ int id;
+};
+
+static struct wccp2_i_see_you_t wccp2_i_see_you;
+
+struct wccp2_item_header_t {
+ uint16_t type;
+ uint16_t length;
+};
+
+static struct wccp2_item_header_t wccp2_item_header;
+
+struct wccp2_router_id_element_t {
+ uint16_t type;
+ uint16_t length;
+ struct in_addr router_addr;
+ uint32_t received_id;
+};
+
+static struct wccp2_router_id_element_t wccp2_router_id_element;
+
+struct wccp2_router_info_t {
+ uint16_t type;
+ uint16_t length;
+ uint32_t member_change;
+};
+
+static struct wccp2_router_info_t wccp2_router_info;
+
+struct wccp2_redirect_assign_t {
+ uint32_t type;
+ uint16_t version;
+ uint16_t length;
+ uint16_t security_type;
+ uint16_t security_length;
+ uint32_t security_option;
+ unsigned char security_implementation[16];
+ uint16_t service_type;
+ uint16_t service_length;
+ uint8_t service;
+ uint8_t serviceid;
+ uint8_t priority;
+ uint8_t protocol;
+ uint32_t service_flags;
+ uint16_t ports[8];
+ uint16_t assignment_type;
+ uint16_t assignment_length;
+ struct in_addr assignment_key;
+ uint32_t assignment_key_change;
+ uint32_t assignment_num_routers;
+ struct in_addr assignment_router1_addr;
+ uint32_t assignment_router1_receive_id;
+ uint32_t assignment_router1_change_number;
+ uint32_t assignment_num_caches;
+ struct in_addr assignment_cache1_addr;
+ char buckets[WCCP_BUCKETS];
+};
+
+static struct wccp2_redirect_assign_t wccp2_redirect_assign;
+
+struct wccp2_assign_bucket_t {
+ int type;
+ int id;
+ int number;
+};
+
+static uint32_t wccp2_received_id;
+static struct in_addr wccp2_router_addr;
+
+
+/* END WCCP V2 */
+
+/*
+ * The functions used during startup:
+ * wccp2Init
+ * wccp2ConnectionOpen
+ * wccp2ConnectionShutdown
+ * wccp2ConnectionClose
+ */
+
+void
+wccp2Init(void)
+{
+ debug(80, 5) ("wccp2Init: Called\n");
+
+ if (Config.Wccp2.service_id < 90 || Config.Wccp2.service_id > 97)
+ {
+ debug(3, 0) ("WARNING: resetting 'wccp2_service_id' to 97\n");
+ Config.Wccp2.service_id = 97;
+ }
+
+ if (eventFind(wccp2HereIam, NULL))
+ return;
+
+ change = 1;
+ wccp2_here_i_am.type = htonl(WCCP2_HERE_I_AM);
+ wccp2_here_i_am.version = htons(WCCP2_VERSION);
+ wccp2_here_i_am.length = htons(sizeof(wccp2_here_i_am)-8);
+ wccp2_here_i_am.security_type = htons(WCCP2_SECURITY_INFO);
+ wccp2_here_i_am.security_length = htons(sizeof(wccp2_here_i_am.security_option)+16);
+ wccp2_here_i_am.security_option = htonl(WCCP2_MD5_SECURITY);
+ wccp2_here_i_am.service_type = htons(WCCP2_SERVICE_INFO);
+ wccp2_here_i_am.service_length = htons(sizeof(wccp2_here_i_am.service) +
+ sizeof(wccp2_here_i_am.serviceid) +
+ sizeof(wccp2_here_i_am.priority) +
+ sizeof(wccp2_here_i_am.protocol) +
+ sizeof(wccp2_here_i_am.service_flags) +
+ sizeof(wccp2_here_i_am.ports));
+ wccp2_here_i_am.service = WCCP2_SERVICE_DYNAMIC;
+ wccp2_here_i_am.serviceid = Config.Wccp2.service_id;
+ wccp2_here_i_am.priority = 0;
+ wccp2_here_i_am.protocol = 6; /* TCP */
+ wccp2_here_i_am.service_flags = htonl(0x0010); /* Ports Defined */
+ wccp2_here_i_am.ports[0] = htons(Config.Wccp2.redirect_port1);
+ wccp2_here_i_am.ports[1] = htons(Config.Wccp2.redirect_port2);
+ wccp2_here_i_am.ports[2] = htons(Config.Wccp2.redirect_port3);
+ wccp2_here_i_am.ports[3] = htons(Config.Wccp2.redirect_port4);
+ wccp2_here_i_am.ports[4] = htons(Config.Wccp2.redirect_port5);
+ wccp2_here_i_am.ports[5] = htons(Config.Wccp2.redirect_port6);
+ wccp2_here_i_am.ports[6] = htons(Config.Wccp2.redirect_port7);
+ wccp2_here_i_am.ports[7] = htons(Config.Wccp2.redirect_port8);
+
+ wccp2_here_i_am.cache_identity_type = htons(WCCP2_WC_ID_INFO);
+ wccp2_here_i_am.cache_identity_length =
+ htons(sizeof(wccp2_here_i_am.cache_identity_addr) +
+ sizeof(wccp2_here_i_am.cache_identity_filler));
+ memset(&wccp2_here_i_am.cache_identity_filler, '\0',
+ sizeof(wccp2_here_i_am.cache_identity_filler));
+ wccp2_here_i_am.cache_view_type = htons(WCCP2_WC_VIEW_INFO);
+ wccp2_here_i_am.cache_view_length = htons(sizeof(wccp2_here_i_am.cache_view_version) +
+ sizeof(wccp2_here_i_am.cache_view_num_routers)+
+ sizeof(wccp2_here_i_am.cache_view_num_caches) +
+ sizeof(wccp2_here_i_am.cache_view_rtr1_addr) +
+ sizeof(wccp2_here_i_am.cache_view_rtr1_receive_id));
+ wccp2_here_i_am.cache_view_version = htonl(1);
+ wccp2_here_i_am.cache_view_num_routers = htonl(1);
+ wccp2_here_i_am.cache_view_rtr1_addr = Config.Wccp2.router;
+ wccp2_here_i_am.cache_view_rtr1_receive_id = wccp2_router_id_element.received_id;
+ wccp2_here_i_am.cache_view_num_caches = htonl(0);
+
+ if (Config.Wccp2.router.s_addr != any_addr.s_addr)
+ if (!eventFind(wccp2HereIam, NULL))
+ eventAdd("wccp2HereIam", wccp2HereIam, NULL, 10.0, 1);
+}
+
+void
+wccp2ConnectionOpen(void)
+{
+ u_short port = WCCP_PORT;
+ struct sockaddr_in router, local;
+ int local_len, router_len;
+ debug(80, 5) ("wccp2ConnectionOpen: Called\n");
+ if (Config.Wccp2.router.s_addr == any_addr.s_addr) {
+ debug(1, 1) ("WCCP Disabled.\n");
+ return;
+ }
+ theInWccpConnection = comm_open(SOCK_DGRAM,
+ 0,
+ Config.Wccp2.incoming,
+ port,
+ COMM_NONBLOCKING,
+ "WCCP Socket");
+ if (theInWccpConnection < 0)
+ fatal("Cannot open WCCP Port");
+ commSetSelect(theInWccpConnection,
+ COMM_SELECT_READ,
+ wccp2HandleUdp,
+ NULL,
+ 0);
+ debug(1, 1) ("Accepting WCCP v2 messages on port %d, FD %d.\n",
+ (int) port, theInWccpConnection);
+ if (Config.Wccp2.outgoing.s_addr != no_addr.s_addr) {
+ theOutWccpConnection = comm_open(SOCK_DGRAM,
+ 0,
+ Config.Wccp2.outgoing,
+ port,
+ COMM_NONBLOCKING,
+ "WCCP Socket");
+ if (theOutWccpConnection < 0)
+ fatal("Cannot open Outgoing WCCP Port");
+ commSetSelect(theOutWccpConnection,
+ COMM_SELECT_READ,
+ wccp2HandleUdp,
+ NULL, 0);
+ debug(1, 1) ("Outgoing WCCP v2 messages on port %d, FD %d.\n",
+ (int) port, theOutWccpConnection);
+ fd_note(theOutWccpConnection, "Outgoing WCCP socket");
+ fd_note(theInWccpConnection, "Incoming WCCP socket");
+ } else {
+ theOutWccpConnection = theInWccpConnection;
+ }
+ router_len = sizeof(router);
+ memset(&router, '\0', router_len);
+ router.sin_family = AF_INET;
+ router.sin_port = htons(port);
+ router.sin_addr = Config.Wccp2.router;
+ if (connect(theOutWccpConnection, (struct sockaddr *) &router, router_len))
+ fatal("Unable to connect WCCP out socket");
+ local_len = sizeof(local);
+ memset(&local, '\0', local_len);
+ if (getsockname(theOutWccpConnection, (struct sockaddr *) &local, &local_len))
+ fatal("Unable to getsockname on WCCP out socket");
+ local_ip.s_addr = local.sin_addr.s_addr;
+}
+
+void
+wccp2ConnectionShutdown(void)
+{
+ if (theInWccpConnection < 0)
+ return;
+ if (theInWccpConnection != theOutWccpConnection) {
+ debug(80, 1) ("FD %d Closing WCCP socket\n", theInWccpConnection);
+ comm_close(theInWccpConnection);
+ }
+ assert(theOutWccpConnection > -1);
+ commSetSelect(theOutWccpConnection, COMM_SELECT_READ, NULL, NULL, 0);
+}
+
+void
+wccp2ConnectionClose(void)
+{
+ wccp2ConnectionShutdown();
+ if (theOutWccpConnection > -1) {
+ debug(80, 1) ("FD %d Closing WCCP socket\n", theOutWccpConnection);
+ comm_close(theOutWccpConnection);
+ }
+}
+
+/*
+ * Functions for handling the requests.
+ */
+
+/*
+ * Accept the UDP packet
+ */
+static void
+wccp2HandleUdp(int sock, void *not_used)
+{
+ struct sockaddr_in from;
+ socklen_t from_len;
+ int len, offset;
+ uint32_t tmp;
+
+ debug(80, 6) ("wccp2HandleUdp: Called.\n");
+
+ commSetSelect(sock, COMM_SELECT_READ, wccp2HandleUdp, NULL, 0);
+ from_len = sizeof(struct sockaddr_in);
+ memset(&from, '\0', from_len);
+ memset(&wccp2_i_see_you, '\0', sizeof(wccp2_i_see_you));
+
+ statCounter.syscalls.sock.recvfroms++;
+
+ len = recvfrom(sock,
+ &wccp2_i_see_you,
+ WCCP_RESPONSE_SIZE,
+ 0,
+ (struct sockaddr *) &from,
+ &from_len);
+
+ if (len < 0)
+ return;
+ if (Config.Wccp2.router.s_addr != from.sin_addr.s_addr)
+ return;
+ if (ntohs(wccp2_i_see_you.version) != WCCP2_VERSION)
+ return;
+ if (ntohl(wccp2_i_see_you.type) != WCCP2_I_SEE_YOU)
+ return;
+
+ debug(80, 1) ("Incoming WCCP v2 I_SEE_YOU length %d.\n",
+ ntohs(wccp2_i_see_you.length));
+ memcpy(&wccp2_item_header, &wccp2_i_see_you.data[0], sizeof(wccp2_item_header));
+ if (ntohs(wccp2_item_header.type) != WCCP2_SECURITY_INFO) {
+ debug(80,1) ("WCCP2_I_SEE_YOU missing WCCP2_SECURITY_INFO\n");
+ return;
+ }
+
+ offset = ntohs(wccp2_item_header.length) + 4;
+ memcpy(&wccp2_item_header, &wccp2_i_see_you.data[offset], sizeof(wccp2_item_header));
+ if (ntohs(wccp2_item_header.type) != WCCP2_SERVICE_INFO) {
+ debug(80,1) ("WCCP2_I_SEE_YOU missing WCCP2_SERVICE_INFO offset %d\n", offset);
+ return;
+ }
+ offset += ntohs(wccp2_item_header.length) + 4; /* Skip WCCP2_SERVICE_INFO */
+ memcpy(&wccp2_item_header, &wccp2_i_see_you.data[offset], sizeof(wccp2_item_header));
+ if (ntohs(wccp2_item_header.type) != WCCP2_ROUTER_ID_INFO) {
+ debug(80,1) ("WCCP2_I_SEE_YOU missing WCCP2_ROUTER_ID_INFO\n");
+ return;
+ }
+ memcpy(&wccp2_router_id_element, &wccp2_i_see_you.data[offset], sizeof(wccp2_router_id_element));
+ debug(80, 1) ("Incoming WCCP2_I_SEE_YOU received id = %d.\n",
+ ntohl(wccp2_router_id_element.received_id));
+
+ wccp2_router_addr = wccp2_router_id_element.router_addr;
+ wccp2_received_id = wccp2_router_id_element.received_id;
+
+ offset += ntohs(wccp2_router_id_element.length) + 4;
+ memcpy (&wccp2_router_info, &wccp2_i_see_you.data[offset], sizeof(wccp2_router_info));
+
+ debug(80, 1) ("Incoming WCCP2_I_SEE_YOU member change = %d tmp=%d.\n",
+ change,ntohl(wccp2_router_info.member_change));
+
+ if (!change) {
+ change = ntohl(wccp2_router_info.member_change);
+ debug(80, 1) ("Incoming WCCP2_I_SEE_YOU member change = %d.\n", change);
+ return;
+ }
+ if (change != ntohl(wccp2_router_info.member_change)) {
+ change = ntohl(wccp2_router_info.member_change);
+ if (wccp2LowestIP())
+ if (!eventFind(wccp2AssignBuckets, NULL))
+ eventAdd("wccp2AssignBuckets", wccp2AssignBuckets, NULL, 25.0, 1);
+ }
+}
+
+static int
+wccp2LowestIP(void)
+{
+/* Force Election for now
+ int loop;
+ for (loop = 0; loop < ntohl(wccp2_i_see_you.number); loop++) {
+ if (wccp2_i_see_you.wccp2_cache_entry[loop].ip_addr.s_addr < local_ip.s_addr)
+ return 0;
+ }
+*/
+ return 1;
+}
+
+static void
+wccp2HereIam(void *voidnotused)
+{
+ debug(80, 6) ("wccp2HereIam: Called\n");
+
+ wccp2_here_i_am.cache_identity_addr = local_ip;
+ wccp2_here_i_am.id = wccp2_i_see_you.id;
+ wccp2_here_i_am.cache_view_rtr1_receive_id = wccp2_received_id;
+ wccp2_here_i_am.cache_view_rtr1_addr = wccp2_router_addr;
+
+ bzero (&wccp2_here_i_am.security_implementation, 16);
+ bzero (wccp_password, 8);
+ strncpy (wccp_password, Config.Wccp2.password, 8);
+
+ MD5Init (&context);
+ MD5Update (&context, wccp_password, 8);
+ MD5Update (&context, &wccp2_here_i_am, sizeof (wccp2_here_i_am));
+ MD5Final (wccp2_here_i_am.security_implementation, &context);
+
+ send(theOutWccpConnection,
+ &wccp2_here_i_am,
+ sizeof(wccp2_here_i_am),
+ 0);
+
+ if (!eventFind(wccp2HereIam, NULL))
+ eventAdd("wccp2HereIam", wccp2HereIam, NULL, 10.0, 1);
+}
+
+static void
+wccp2AssignBuckets(void *voidnotused)
+{
+ struct wccp2_assign_bucket_t wccp2_assign_bucket;
+ int buckets_per_cache;
+ int loop;
+ int number_caches;
+ int bucket = 0;
+ int *caches;
+ int offset;
+ char buckets[WCCP_BUCKETS];
+
+ if (Config.Wccp2.service_id < 90 || Config.Wccp2.service_id > 97)
+ {
+ debug(3, 0) ("WARNING: resetting 'wccp2_service_id' to 97\n");
+ Config.Wccp2.service_id = 97;
+ }
+
+ debug(80, 6) ("wccp2AssignBuckets: Called\n");
+ debug(80, 1) ("WCCP2 Assigning Redirect\n");
+ memset(&wccp2_redirect_assign.buckets, '\0', sizeof(wccp2_redirect_assign.buckets));
+ memset(&wccp2_redirect_assign.buckets, 0xFF, WCCP_BUCKETS);
+ for (bucket = 0; bucket < WCCP_BUCKETS; bucket++) {
+ wccp2_redirect_assign.buckets[bucket] = 0;
+ }
+ wccp2_redirect_assign.type = htonl(WCCP2_REDIRECT_ASSIGN);
+ wccp2_redirect_assign.version = htons(WCCP2_VERSION);
+ wccp2_redirect_assign.length = htons(sizeof(wccp2_redirect_assign)-8);
+ wccp2_redirect_assign.security_type = htons(WCCP2_SECURITY_INFO);
+ wccp2_redirect_assign.security_length = htons(sizeof(wccp2_redirect_assign.security_option)+16);
+ wccp2_redirect_assign.security_option = htonl(WCCP2_MD5_SECURITY);
+ wccp2_redirect_assign.service_type = htons(WCCP2_SERVICE_INFO);
+ wccp2_redirect_assign.service_length = htons(sizeof(wccp2_redirect_assign.service) +
+ sizeof(wccp2_redirect_assign.serviceid) +
+ sizeof(wccp2_redirect_assign.priority) +
+ sizeof(wccp2_redirect_assign.protocol) +
+ sizeof(wccp2_redirect_assign.service_flags) +
+ sizeof(wccp2_redirect_assign.ports));
+
+ wccp2_redirect_assign.service = WCCP2_SERVICE_DYNAMIC;
+ wccp2_redirect_assign.serviceid = Config.Wccp2.service_id;
+ wccp2_redirect_assign.priority = 0;
+ wccp2_redirect_assign.protocol = 6; /* TCP */
+ wccp2_redirect_assign.service_flags = htonl(0x0010); /* Ports Defined */
+ wccp2_redirect_assign.ports[0] = htons(Config.Wccp2.redirect_port1);
+ wccp2_redirect_assign.ports[1] = htons(Config.Wccp2.redirect_port2);
+ wccp2_redirect_assign.ports[2] = htons(Config.Wccp2.redirect_port3);
+ wccp2_redirect_assign.ports[3] = htons(Config.Wccp2.redirect_port4);
+ wccp2_redirect_assign.ports[4] = htons(Config.Wccp2.redirect_port5);
+ wccp2_redirect_assign.ports[5] = htons(Config.Wccp2.redirect_port6);
+ wccp2_redirect_assign.ports[6] = htons(Config.Wccp2.redirect_port7);
+ wccp2_redirect_assign.ports[7] = htons(Config.Wccp2.redirect_port8);
+
+ wccp2_redirect_assign.assignment_type = htons(WCCP2_REDIRECT_ASSIGNMENT);
+ wccp2_redirect_assign.assignment_length =
+ htons(sizeof(wccp2_redirect_assign.assignment_key) +
+ sizeof(wccp2_redirect_assign.assignment_key_change) +
+ sizeof(wccp2_redirect_assign.assignment_num_routers) +
+ sizeof(wccp2_redirect_assign.assignment_router1_addr) +
+ sizeof(wccp2_redirect_assign.assignment_router1_receive_id) +
+ sizeof(wccp2_redirect_assign.assignment_router1_change_number) +
+ sizeof(wccp2_redirect_assign.assignment_num_caches) +
+ sizeof(wccp2_redirect_assign.assignment_cache1_addr) +
+ sizeof(wccp2_redirect_assign.buckets));
+ wccp2_redirect_assign.assignment_key = wccp2_here_i_am.cache_identity_addr;
+ wccp2_redirect_assign.assignment_key_change = htonl(change);
+ wccp2_redirect_assign.assignment_num_routers = htonl(1);
+ wccp2_redirect_assign.assignment_router1_addr = wccp2_router_addr;
+ wccp2_redirect_assign.assignment_router1_receive_id = wccp2_received_id;
+ wccp2_redirect_assign.assignment_router1_change_number = htonl(change);
+ wccp2_redirect_assign.assignment_num_caches = htonl(1);
+ wccp2_redirect_assign.assignment_cache1_addr = wccp2_here_i_am.cache_identity_addr;
+
+ bzero (&wccp2_redirect_assign.security_implementation, 16);
+ bzero (wccp_password, 8);
+ strncpy (wccp_password, Config.Wccp2.password, 8);
+
+ MD5Init (&context);
+ MD5Update (&context, wccp_password, 8);
+ MD5Update (&context, &wccp2_redirect_assign, sizeof(wccp2_redirect_assign));
+ MD5Final (wccp2_redirect_assign.security_implementation, &context);
+
+ send(theOutWccpConnection,
+ &wccp2_redirect_assign,
+ sizeof(wccp2_redirect_assign),
+ 0);
+ change = 0;
+}
+
+#endif /* USE_WCCPv2 */
+