Initial hack at TPROXY v4 support in Squid-3

This patch removes the --enable-linux-tproxy configure option and replaces
it with two alternatives --enable-linux-tproxy2 and --enable-linux-tproxy4

*-tproxy2 performs the original tproxy behaviour of squid.

*-tproxy4 adds and uses the new IP_TRANSPARENT socket option available
in kernel 2.6.26 for the netfilter TPROXY target.


TODOs:
        - need to make TPROXY and REDIRECT targets dual-operable
          (that will make --enable-linux-netfilter =~= --enable-linux-tproxy4)
        - still need to make squid bind outbound with client address
        - maybe make IPInterception.* a class to handle transparent API
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [EMAIL PROTECTED]
# target_branch: file:///src/squid/bzr/trunk/
# testament_sha1: c15fc2a03b9d847977021f33bf29cb22a5821752
# timestamp: 2008-04-01 12:16:41 +1200
# base_revision_id: [EMAIL PROTECTED]
#   so853tluhwlx6qc5
# 
# Begin patch
=== modified file 'configure.in'
--- configure.in	2008-03-18 11:58:16 +0000
+++ configure.in	2008-03-26 11:49:34 +0000
@@ -1219,13 +1219,26 @@
 fi
 
 dnl Enable Linux transparent proxy support
-AC_ARG_ENABLE(linux-tproxy,
-[  --enable-linux-tproxy
-			  Enable real Transparent Proxy support for Netfilter TPROXY.],
-[ if test "$enableval" = "yes" ; then
-	echo "Linux Netfilter/TPROXY enabled"
-	AC_DEFINE(LINUX_TPROXY, 1, [Enable real Transparent Proxy support for Netfilter TPROXY.])
-	LINUX_TPROXY="yes"
+AC_ARG_ENABLE(linux-tproxy2,
+[  --enable-linux-tproxy2
+			  Enable real Transparent Proxy support for Netfilter TPROXY (version 2).],
+[ if test "$enableval" = "yes" ; then
+	echo "Linux Netfilter/TPROXY v2 enabled"
+	AC_DEFINE(LINUX_TPROXY2, 1, [Enable real Transparent Proxy support for Netfilter TPROXY v2.])
+	LINUX_TPROXY2="yes"
+        if test -z "$LINUX_NETFILTER"; then
+	    echo "Linux-Netfilter Transparent Proxy automatically enabled"
+	    LINUX_NETFILTER="yes"
+	fi
+  fi
+])
+AC_ARG_ENABLE(linux-tproxy4,
+[  --enable-linux-tproxy4
+			  Enable real Transparent Proxy support for Netfilter TPROXY (version 4+).],
+[ if test "$enableval" = "yes" ; then
+	echo "Linux Netfilter/TPROXY v4 enabled"
+	AC_DEFINE(LINUX_TPROXY4, 1, [Enable real Transparent Proxy support for Netfilter TPROXY v4.])
+	LINUX_TPROXY4="yes"
         if test -z "$LINUX_NETFILTER"; then
 	    echo "Linux-Netfilter Transparent Proxy automatically enabled"
 	    LINUX_NETFILTER="yes"
@@ -2882,25 +2895,26 @@
     sleep 10
 fi
 
-dnl Linux Netfilter/TPROXY support requires some specific header files
+dnl Linux Netfilter/TPROXYv2 support requires some specific header files
 dnl Shamelessly copied from shamelessly copied from above
-if test "$LINUX_TPROXY" ; then
-    AC_MSG_CHECKING(if TPROXY header files are installed)
+if test "$LINUX_TPROXY2" ; then
+    AC_MSG_CHECKING(if TPROXYv2 header files are installed)
     # hold on to your hats...
     if test "$ac_cv_header_linux_netfilter_ipv4_ip_tproxy_h" = "yes" && test "$LINUX_NETFILTER" = "yes"; then
-	LINUX_TPROXY="yes"
-	AC_DEFINE(LINUX_TPROXY, 1, [Enable real Transparent Proxy support for Netfilter TPROXY.])
+	LINUX_TPROXY2="yes"
+	AC_DEFINE(LINUX_TPROXY2, 1, [Enable real Transparent Proxy support for Netfilter TPROXY v2.])
     else
-	LINUX_TPROXY="no"
-	AC_DEFINE(LINUX_TPROXY, 0, [Enable real Transparent Proxy support for Netfilter TPROXY.])
-    fi
-    AC_MSG_RESULT($LINUX_TPROXY)
-fi
-if test "$LINUX_TPROXY" = "no" && test "$LINUX_NETFILTER" = "yes"; then
-    echo "WARNING: Cannot find TPROXY headers, you need to install the"
-    echo "tproxy package from:"
-    echo " - lynx http://www.balabit.com/downloads/tproxy/";
-    sleep 10
+	LINUX_TPROXY2="no"
+	AC_DEFINE(LINUX_TPROXY2, 0, [Enable real Transparent Proxy support for Netfilter TPROXY v2.])
+    fi
+    AC_MSG_RESULT($LINUX_TPROXY2)
+    if test "$LINUX_TPROXY2" = "no" && test "$LINUX_NETFILTER" = "yes"; then
+        echo "WARNING: Cannot find TPROXY v2 headers, you need to install the"
+        echo "tproxy package from:"
+        echo " - lynx http://www.balabit.com/downloads/tproxy/";
+        echo "Or select the '--enable-linux-tproxy4' option instead."
+        sleep 10
+    fi
 fi
 
 if test -z "$USE_GNUREGEX" ; then

=== modified file 'doc/release-notes/release-3.1.sgml'
--- doc/release-notes/release-3.1.sgml	2008-01-17 17:09:05 +0000
+++ doc/release-notes/release-3.1.sgml	2008-03-29 11:23:47 +0000
@@ -298,6 +298,16 @@
 	   but please report the bugs anyway.
         </p>
 
+	<tag>--enable-linux-tproxy2</tag>
+	<p>New option to enable TPROXY version 2 support in squid (previously known as --enable-linux-tproxy).
+	Linux Kernel patches from Balabit are required before building squid with this option.
+	</p>
+
+	<tag>--enable-linux-tproxy4</tag>
+	<p>New option to enable TPROXY version 4+ support in squid.
+	This options requires a linux kernel 2.6.25 or later for embeded netfilter TPROXY targets.
+	</p>
+
 </descrip>
 </p>
 
@@ -308,7 +318,7 @@
 	<tag>--disable-internl-dns</tag>
 	<p>Better support for Linux using the external DNS helper.
            The helper will compile and work with dns_nameservers on more variants of Linux than previously.</p>
- 
+
 </descrip>
 </p>
 
@@ -334,6 +344,8 @@
 <p>The following configure options have been removed.
 
 <descrip>
+	<tag>--enable-linux-tproxy</tag>
+	<p>Replaced by --enable-linux-tproxy2 to make way for differences in TPROXY v2 and v4 support.</p>
 
 </descrip>
 

=== modified file 'include/autoconf.h.in'
--- include/autoconf.h.in	2008-02-17 16:24:48 +0000
+++ include/autoconf.h.in	2008-03-26 11:49:34 +0000
@@ -792,8 +792,11 @@
 /* Enable support for Transparent Proxy on Linux (Netfilter) systems */
 #undef LINUX_NETFILTER
 
-/* Enable real Transparent Proxy support for Netfilter TPROXY. */
-#undef LINUX_TPROXY
+/* Enable real Transparent Proxy support for Netfilter TPROXY v2. */
+#undef LINUX_TPROXY2
+
+/* Enable real Transparent Proxy support for Netfilter TPROXY v4. */
+#undef LINUX_TPROXY4
 
 /* If we need to declare sys_errlist[] as external */
 #undef NEED_SYS_ERRLIST

=== modified file 'src/IPInterception.cc'
--- src/IPInterception.cc	2008-02-06 05:38:24 +0000
+++ src/IPInterception.cc	2008-03-26 11:49:34 +0000
@@ -1,4 +1,3 @@
-
 /*
  * $Id: IPInterception.cc,v 1.20 2008/02/05 22:38:24 amosjeffries Exp $
  *
@@ -88,11 +87,12 @@
 #include <linux/netfilter_ipv4.h>
 #endif
 
-#if IPF_TRANSPARENT
 int
-
 clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst)
 {
+
+#if IPF_TRANSPARENT  /* --enable-ipf-transparent */
+
     dst = me;
     if( !me.IsIPv4() ) return -1;
     if( !peer.IsIPv4() ) return -1;
@@ -198,12 +198,11 @@
 
         return 0;
     }
-}
-
-#elif LINUX_NETFILTER
-int
-clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst)
-{
+
+
+
+#elif LINUX_NETFILTER || LINUX_TPROXY4  /* --enable-linux-netfilter OR --enable-linux-tproxy4 */
+
     dst = me;
     if( !me.IsIPv4() ) return -1;
     if( !peer.IsIPv4() ) return -1;
@@ -213,12 +212,16 @@
 
     dst.GetAddrInfo(lookup,AF_INET);
 
+#if LINUX_NETFILTER
     if (getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, lookup->ai_addr, &lookup->ai_addrlen) != 0)
+#elif LINUX_TPROXY4
+    if (getsockopt(fd, SOL_IP, IP_TRANSPARENT, lookup->ai_addr, &lookup->ai_addrlen) != 0)
+#endif
     {
         dst.FreeAddrInfo(lookup);
 
         if (squid_curtime - last_reported > 60) {
-            debugs(89, 1, "clientNatLookup: peer " << peer << " NF getsockopt(SO_ORIGINAL_DST) failed: " << xstrerror());
+            debugs(89, 1, "clientNatLookup: peer " << peer << " NF getsockopt(" << (LINUX_NETFILTER?"SO_ORIGINAL_DST":"IP_TRANSPARENT") << ") failed: " << xstrerror());
             last_reported = squid_curtime;
         }
 
@@ -234,13 +237,9 @@
         return 0;
     else
         return -1;
-}
-
-#elif PF_TRANSPARENT
-int
-
-clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress dst)
-{
+
+
+#elif PF_TRANSPARENT  /* --enable-pf-transparent */
 
     struct pfioc_natlook nl;
     static int pffd = -1;
@@ -300,12 +299,10 @@
         else
             return -1;
     }
-}
-
-#elif IPFW_TRANSPARENT
-int
-clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst)
-{
+
+
+#elif IPFW_TRANSPARENT /* --enable-ipfw-transparent */
+
     int ret;
     struct addrinfo *lookup = NULL;
 
@@ -330,14 +327,13 @@
     dst.FreeAddrInfo(lookup);
 
     return 0;
-}
-
-#else
-int
-clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst)
-{
+
+
+#else /* none of the transparent options configured */
+
     debugs(89, 1, "WARNING: transparent proxying not supported");
     return -1;
+
+#endif
+
 }
-#endif
-

=== modified file 'src/IPInterception.h'
--- src/IPInterception.h	2007-12-15 06:11:41 +0000
+++ src/IPInterception.h	2008-03-26 11:49:34 +0000
@@ -1,4 +1,3 @@
-
 /*
  * $Id: IPInterception.h,v 1.7 2007/12/14 23:11:45 amosjeffries Exp $
  *
@@ -30,13 +29,15 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
-
 #ifndef SQUID_IPINTERCEPTION_H
 #define SQUID_IPINTERCEPTION_H
 
 #include "IPAddress.h"
 
-SQUIDCEXTERN int
-clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst);
+#if LINUX_TPROXY4 && !defined(IP_TRANSPARENT)
+#define IP_TRANSPARENT 19
+#endif
+
+SQUIDCEXTERN int clientNatLookup(int fd, const IPAddress &me, const IPAddress &peer, IPAddress &dst);
 
 #endif /* SQUID_IPINTERCEPTION_H */

=== modified file 'src/ProtoPort.h'
--- src/ProtoPort.h	2008-03-16 21:48:45 +0000
+++ src/ProtoPort.h	2008-03-26 11:49:34 +0000
@@ -31,7 +31,8 @@
 
     int vport;                 /* virtual port support, -1 for dynamic, >0 static*/
     int disable_pmtu_discovery;
-#if LINUX_TPROXY
+
+#if LINUX_TPROXY2 || LINUX_TPROXY4
     unsigned int tproxy:1; /* spoof client ip using tproxy */
 #endif
 

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2008-03-20 23:20:58 +0000
+++ src/cache_cf.cc	2008-03-31 10:45:54 +0000
@@ -1,4 +1,3 @@
-
 /*
  * $Id: cache_cf.cc,v 1.544 2008/03/04 12:00:36 amosjeffries Exp $
  *
@@ -2928,10 +2927,11 @@
         else
             self_destruct();
 
-#if LINUX_TPROXY
+#if LINUX_TPROXY2 || LINUX_TPROXY4
 
     } else if (strcmp(token, "tproxy") == 0) {
         s->tproxy = 1;
+        s->transparent = 1;
         need_linux_tproxy = 1;
 #if USE_IPV6
         /* INET6: until transparent REDIRECT works on IPv6 SOCKET, force wildcard to IPv4 */
@@ -2941,6 +2941,7 @@
         }
 #endif
 #endif
+
     } else if (strcmp(token, "ipv4") == 0) {
 #if USE_IPV6
         if( !s->s.SetIPv4() ) {

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2008-03-16 21:48:45 +0000
+++ src/client_side.cc	2008-03-26 11:49:34 +0000
@@ -2213,8 +2213,7 @@
 
     request->flags.transparent = http->flags.transparent;
 
-#if LINUX_TPROXY
-
+#if LINUX_TPROXY2 || LINUX_TPROXY4
     request->flags.tproxy = conn->port->tproxy && need_linux_tproxy;
 #endif
 
@@ -3118,6 +3117,13 @@
         if (fd < 0)
             continue;
 
+#if LINUX_TPROXY4
+        /* because the transparent/non-transparent port info is only known here.
+         * we have to set the IP_TRANSPARENT option here. */
+        if(s->transparent)
+            comm_set_transparent(fd,0);
+#endif
+
         comm_listen(fd);
 
         comm_accept(fd, httpAccept, s);

=== modified file 'src/comm.cc'
--- src/comm.cc	2008-03-25 15:40:36 +0000
+++ src/comm.cc	2008-03-31 10:45:54 +0000
@@ -48,6 +48,7 @@
 #include "SquidTime.h"
 #include "CommCalls.h"
 #include "IPAddress.h"
+#include "IPInterception.h"
 
 #if defined(_SQUID_CYGWIN_)
 #include <sys/ioctl.h>
@@ -627,6 +628,23 @@
 #endif /* sockopt */
 }
 
+void
+comm_set_transparent(int fd)
+{
+#if LINUX_TPROXY4
+    int tos = 1;
+    if (setsockopt(fd, SOL_IP, IP_TRANSPARENT, (char *) &tos, sizeof(int)) < 0) {
+        debugs(50, DBG_IMPORTANT, "comm_open: setsockopt(IP_TRANSPARENT) on FD " << fd << ": " << xstrerror());
+    }
+    else {
+        /* mark the socket as having transparent options */
+        fd_table[fd].flags.transparent = 1;
+    }
+#else
+    debugs(50, DBG_CRITICAL, "WARNING: comm_open: setsockopt(IP_TRANSPARENT) not supported on this platform");
+#endif /* sockopt */
+}
+
 /**
  * Create a socket. Default is blocking, stream (TCP) socket.  IO_TYPE
  * is OR of flags specified in defines.h:COMM_*
@@ -1307,6 +1325,14 @@
 
     commSetNonBlocking(sock);
 
+#if LINUX_TPROXY4
+    /* AYJ: do we need to set this again on every accept? */
+    if(fd_table[fd].flags.transparent == 1) {
+        comm_set_transparent(sock, 0);
+        F->flags.transparent = 1;
+    }
+#endif
+
     PROF_stop(comm_accept);
     return sock;
 }

=== modified file 'src/comm.h'
--- src/comm.h	2008-02-13 05:58:29 +0000
+++ src/comm.h	2008-03-26 12:02:56 +0000
@@ -56,6 +56,11 @@
 SQUIDCEXTERN u_short comm_local_port(int fd);
 SQUIDCEXTERN int comm_set_tos(int fd, int tos);
 
+/**
+ * Set the socket IP_TRANSPARENT option for Linux TPROXY v4 support.
+ */
+SQUIDCEXTERN void comm_set_transparent(int fd, int tos);
+
 SQUIDCEXTERN void commSetSelect(int, unsigned int, PF *, void *, time_t);
 SQUIDCEXTERN void commResetSelect(int);
 

=== modified file 'src/fde.h'
--- src/fde.h	2008-02-13 06:22:13 +0000
+++ src/fde.h	2008-03-31 04:01:31 +0000
@@ -82,6 +82,9 @@
 	unsigned int close_on_exec:1;
 	unsigned int read_pending:1;
 	unsigned int write_pending:1;
+#if LINUX_TPROXY4
+        unsigned int transparent:1;
+#endif
     } flags;
 
     int64_t bytes_read;

=== modified file 'src/forward.cc'
--- src/forward.cc	2008-03-16 21:48:45 +0000
+++ src/forward.cc	2008-03-26 11:49:34 +0000
@@ -49,8 +49,12 @@
 #include "SquidTime.h"
 #include "Store.h"
 
-#if LINUX_TPROXY
+#if LINUX_TPROXY2
+#ifdef HAVE_LINUX_NETFILTER_IPV4_IP_TPROXY_H
 #include <linux/netfilter_ipv4/ip_tproxy.h>
+#else
+#error " TPROXY v2 Header file missing: linux/netfilter_ipv4/ip_tproxy.h. Perhapse you meant to use TPROXY v4 ? "
+#endif
 #endif
 
 static PSC fwdStartCompleteWrapper;

=== modified file 'src/forward.h'
--- src/forward.h	2008-03-16 22:10:18 +0000
+++ src/forward.h	2008-03-26 11:49:34 +0000
@@ -99,7 +99,7 @@
         unsigned int ftp_pasv_failed:1;
         unsigned int forward_completed:1;
     } flags;
-#if LINUX_NETFILTER
+#if LINUX_NETFILTER || LINUX_TPROXY2 || LINUX_TPROXY4
     IPAddress src;
 #endif
 

=== modified file 'src/globals.h'
--- src/globals.h	2008-03-20 11:30:19 +0000
+++ src/globals.h	2008-03-26 11:49:34 +0000
@@ -185,7 +185,7 @@
     extern const char *external_acl_message;      /* NULL */
     extern int opt_send_signal;	/* -1 */
     extern int opt_no_daemon; /* 0 */
-#if LINUX_TPROXY
+#if LINUX_TPROXY2 || LINUX_TPROXY4
     extern int need_linux_tproxy; /* 0 */
 #endif
 

=== modified file 'src/http.cc'
--- src/http.cc	2008-02-13 06:55:26 +0000
+++ src/http.cc	2008-03-26 11:49:34 +0000
@@ -1229,7 +1229,8 @@
 	    comm_remove_close_handler(fd, closeHandler);
             closeHandler = NULL;
             fwd->unregister(fd);
-#if LINUX_TPROXY
+
+#if LINUX_TPROXY2 || LINUX_TPROXY4
 
             if (orig_request->flags.tproxy)
                 client_addr = orig_request->client_addr;

=== modified file 'src/structs.h'
--- src/structs.h	2008-03-20 23:20:58 +0000
+++ src/structs.h	2008-03-26 11:49:34 +0000
@@ -1029,7 +1029,7 @@
 #if HTTP_VIOLATIONS
         nocache_hack = 0;
 #endif
-#if LINUX_TPROXY
+#if LINUX_TPROXY2 || LINUX_TPROXY4
 	tproxy = 0;
 #endif
     }
@@ -1051,7 +1051,7 @@
 #endif
     unsigned int accelerated:1;
     unsigned int transparent:1;
-#if LINUX_TPROXY
+#if LINUX_TPROXY2 || LINUX_TPROXY4
     unsigned int tproxy:1; /* spoof client ip using tproxy */
 #endif
     unsigned int internal:1;

=== modified file 'src/tools.cc'
--- src/tools.cc	2008-03-20 23:20:58 +0000
+++ src/tools.cc	2008-03-26 11:49:34 +0000
@@ -1236,7 +1236,7 @@
 
     if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
         /* Silent failure unless TPROXY is required. Maybe not started as root */
-#if LINUX_TPROXY
+#if LINUX_TPROXY2 || LINUX_TPROXY4
 
         if (need_linux_tproxy)
             debugs(1, 1, "Error - tproxy support requires capability setting which has failed.  Continuing without tproxy support");
@@ -1246,7 +1246,6 @@
 #endif
 
     }
-
 #endif
 }
 
@@ -1273,10 +1272,13 @@
 
     cap->inheritable = 0;
     cap->effective = (1 << CAP_NET_BIND_SERVICE);
-#if LINUX_TPROXY
 
+#if LINUX_TPROXY2
     if (need_linux_tproxy)
         cap->effective |= (1 << CAP_NET_ADMIN) | (1 << CAP_NET_BROADCAST);
+#elif LINUX_TPROXY4
+    if (need_linux_tproxy)
+        cap->effective |= (1 << CAP_NET_ADMIN);
 
 #endif
 
@@ -1285,7 +1287,7 @@
 
     if (capset(head, cap) != 0) {
         /* Silent failure unless TPROXY is required */
-#if LINUX_TPROXY
+#if LINUX_TPROXY2 || LINUX_TPROXY4
 
         if (need_linux_tproxy)
             debugs(50, 1, "Error enabling needed capabilities. Will continue without tproxy support");
@@ -1299,14 +1301,14 @@
 nocap:
     xfree(head);
     xfree(cap);
-#else
-#if LINUX_TPROXY
+#else /* not defined(_SQUID_LINUX_) && HAVE_SYS_CAPABILITY_H */
+
+#if LINUX_TPROXY2 || LINUX_TPROXY4
 
     if (need_linux_tproxy)
         debugs(50, 1, "Missing needed capability support. Will continue without tproxy support");
 
     need_linux_tproxy = 0;
-
 #endif
 
 #endif

# Begin bundle
IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWa9y1S4AGuDfgEZyff//////
/+q////+YCFdxb3dN1xxXb2rVLPvvdvL3u7fceSezXzbM+7VCbDds7boPu7ltttprTLL3XanfbtG
9au1tXd24uWoFXY93TkvNbu3rwdAZSl6UNUq2xq2q1p20glEBACZMjQCYJpNNMmJNDU00ek2p6aj
RoAMRhKETCZGjRIyp+kJtIGQBoAaAADQGgaANNAmpGiZCeKaAP1QADQAAAADQAGgSIgICmkep6FT
9U/VPVG9U8GkTPUaI2oHqPUDQAxAN6gikICTGpiZMmibSbSNMRlPJNNJp6NE00aaMgA0AKkoAE0B
BMp6FPTRqbSm2qMQ02iPUNNGRoaABoVv4DSEQXGMYkT5a/66o8XWgeUesoWK4PPPmfVwMZUnD/NS
WGRiMLsDhODxjyNVEa5us5kSZZnYyvJADJmIfWUZd3M7v3crvcgGf76B8Im7SSSWLZetjcVAyG+p
lkCfR9WnY07Lwu4N6HE6RuB9obqn+hchP7V8aLQ3e86VW09h39PH/ilNPCFrHnNTwUekTUleZq7t
Xsj4RdR3Odpyi62MWkZ1PncZHzpYoxRVRcuTVPhGNpO2M+H0wZY/P186jeLilIlKSMKN6EKcdtpi
wfVm2nbPfoeJa1shSSrqzQ19Rde4Aya+2BtMEQC+oDliloFuxBEQS9mkT+qEhETY5GOO4ZFeoAYj
WJzGM0SwFCcb1F1XK7ARdaiKsJxIAzUtTc1gXdQXCkvdBs0hsUvaBTkJESQk4ZeE4XHIgk+kEAk+
mCIRD8T78UUKXfJ7+n4H5+9+lmz0KDU4RQ2oe5ipZTz8IKiDSLISPO/Wu9T8DLYU11x4Rox8jbTh
7+5r2/9jxqqspywaTNeoH9kTeiQpDbGNtsBttNibSXVwxshkMTbY2222htuGvDwPAPwe8AXy/RA/
L56P5+/dbNLdwQ02NDE291sjX/3S6+hj1ja2Z2daVkLfSRd8ZKvzlUhi5GIllCTiupmamEzR0Wh1
yoLwA7XrfV85x+lZ5FU+WFiGC43YZS4gFTGNUDBC6IsursaMmRMu+U2JlAzs1RKMIWqWCik4gAoq
yWFGTpCMxm4V02LmsuoY10rZEvXTWJLVo43BKlJxKHN2Jqqbnc2SWUUVq1pgMdlOMMDgNlUQwNu1
iqtOv8dPTSbR5nNnokxjQPGbi5rmuStA/NUXxYhpDSbt6Yt6oAusxf5MIKGhzSbBjn2OB+LDGI1Q
MQq7h43Noxaq/lhpXNV89odA+SBpjUQqbFnpKKsaCfToJw0TQARSt3L+0rQK6Y/ligNQH44r9zM7
valDh3y0o5pvjL8+kjZAnGljXx8Z/XHn8NqhMgKCDW0vNBZ3vaNtgXWp9P/xr6VZ6Mrq0RDbwv3S
GTuQRFwF7gY2NjY2NjY2Gmep00D2dicuwpbHitmQDX8lqLTj2ZUMoAjp1uoZwhVV9aD/OJoIGern
EWFtPRz7+O5Iuw+/brXrbyVe33oaf1cpD7CMqyqpdq+qV3pkkXx6tns8fJz3vf5nlFj3v82Q9/Ga
S1nu8K6ISmQzfK0RnMxac0ClAkhdbcOyoi1PYQe4XlRd5Io20xobOiRs6sy0nOz+Z5dXo18H6PXx
+HaDCnJQcr1TKLcr1fhPOz+wx1M2vCEtd5vfDNqXhfS98s9I3xMH8RPVXzT3EQQGHdXZlWlrW11v
sgdpAsIWXrsLPtslglUhSkSqgiqKn2v0UI+Q6YO9qDBCBcnPIw9fHHi0403UCf4hORNNzL8p/Oo4
dAUYo1T8SKqvDzrhToyx3V9n5eR6zEmCgnKChMs/ay9ikVos0avfRNlQ+xhlQTmVXc8U9brzY8rj
hP0GkXyLKvqYLikS8IL+JlkA/XD8JEu7vv4+3gnKlKHiqHtGcMgZ+EGcJZ+DcSUAj6j54k+KnUPe
NNJsSQ00IDxSR8u8CD4vZxEC1N7COShVsRDsfrMDytPcoe9vS6YkH1C362pwIKxN7CWyMgmA07oa
y/WGFuhdlMSfz/vvVnktTVUTZt90reKsb2748r74PvTLhVbIsri1XVOYpSZctmO6vu75FZDEqlCh
UsaiQB8oQTWjvaAqSSVFR67nRUwVqc6IBobx7EbdYe32n7ybL3yUDWnx7PcqauHTjkhkja5gbFP2
oEc7BERuDEDRfnERjFVVVVVVVVVVVVCqoh0OrbyYcTkbGtxwrTBaEAVZtRLwQhVYrtIuxDYkqss1
Zg2rsSPZcpTdxdBZH2OgP2hARnA0hjSuM+JO1iiKmSEkgJPwkk1e9T5joU50ObaoWTUdZPmVaxpG
0liahNJs0WQ+5g+hYv1q5waaRSkBprcvX8G1iS3LRxXDhHxCXrNLreFI2ODYoTYgZrQvBRYBzyUO
SnFWoIsQlkMECMBqwypKlS4y1SwZGQViEkgIbsrVq5VYsr5NZTZxUwbCcFQw4sXRxZuC5mzPGGBa
ZOEvbnF+iH9nQ6NHB9bpBzcr3WagOU8BK9lZsIdWmiqYozkOSIiVUREo9cSx0hJUnNqMrAUaSbrV
2tTp0+upt6bi3nPYg/LqBuuCyOFyMFC4+1ZwFf0RhMyIanJUJcLpxYT1/G7Biz1RaKhvx3s9rG9F
5RHhnEIQYk634KFrDNDYFhUdIQcHd72g3VigqaoCoFSRNwQFMjxMKvaI4S68r4Tgb3yc92E8yWLP
fRsdomMNpoDDjQtZ7MqilQRalDIcl4SpMEcijBYsI3cjixxyYhZeygDGhY0JZgZhKDrT94pRShBY
+cnVkIp3kpDfyC5oP1kQXiYpCZ0bhjlYsFzN9x4xehcqTNWetJbjDtatexAbp4FIZ6yR2IZHQbXe
pscWguOcsl7l0eLyEmdLajCOfOBq7OTNk6NnNacTN2YmSnN3O9c1XPjg7ncrkqcWKxisNohI0EU7
RCdOzfvBLhcwfCE9JB2JVEapkWpRtDjIX6PPatfvow99ELYrrNqwrS1iKnndBwziSFq0uhvN3llc
XyzhbCkWqjBdPJ6zaTpcb3MEyoHEJgC2qHkpg1Thj77XguuaqlzC7FcEsmaxnmEtXDdSRjRywbiN
Kpg8KwQIkATy0SZNRxXXi07BWr3MEbUCCD0xuPKqn6bQuB7FRWKJGpgpqVGd7nFKZ3oJIwXDzNCM
sAzzxcrgZmrwd5hFB7jwNaZN0IsIpUotZ1CTc7opzNaRhCX3S6CeSy1wWbKkpf8zi0benNJNJEeP
jOrR4GDqxavGYOy5zbr+XZmpk2au8wYMx48mJi8w9tpop1IFRUIZ0seiMQrqaxwWtK43WJYxOL1K
UmG6xRgoAFfn1DKs1NTpoXKMNiNjBSpoRWaltb1lWBRQFEQBPahQZcOB+s2OTU8V9y2tIe9kEhRa
BrKrxUrdVhALfyNJoDYkhliFQpSUAr8Gpk+nvS23p0md+6bSaTbYjGxFN2aNFrZ0dWD6kY5GO2dR
AZi+5lY0QIOqXJD1MABNKBEobMWHEljxnMFNTG5qWJsIgvBc7jJcdKt9DfNhGhK4Mr6Vs2xRczxy
btp2iBz+bZu3bNnksaHswc1zi5rHjDJe4r1MTFS9m2XOLkzXkhSSlo89sRgh7E74FCY68TGeizK7
cCakWKoqiz6hxeLyFcdNK2ybec62HGix7TGINNtHuu/e/A86pDfgNq1saahhnbw4rllhPxMM/XY5
PBZAYQuGbVXDBkRp8S+ymc5HIYGIpxY2MDDMxKvU1b4Z1a6PXDiyXsG65yc174OWK6XcHwmS3Z1U
sLLJTnxmbm3HL28Gb3I2yh0Mp0btNO4ucGDv6ac4Xo5LtZfOfByaBLr8+tdLpwd33l7Jk92uFuUQ
20PFZa0WwPRHp+7suU3bMVrq7ODFeuL3RHuyXOLB1d/mEp8HcWpo4WnVfnOkTCMc7wGMtLzsM661
qXZDwwsiNZQlxtRujxZ9MfcQbMXk1O3e4b0ypCd8cJ6e8K+zBkcTIKc3ZpwLkRxUvKJgMdWl3GxO
oww4znRejVes3i5UkU0WssXAJe3aSngsWX618Oa5pNIzxcBrbnkvaMV7KzKL1K7ul9/k2ZjLIJj6
M4dFAzL7lihbLCIaUMQiblTslBsJYY9ZMrjvp1OC/VL5LmSjLlzgwbm4yx7CAs7nZ2XlrkxXOMza
Oql7FqvcujndSrFOqp3bGndGTtgCVENfOBvMR1exdON0e2rSRIvXbjJ0H0uYv3DtpZ0rUxrf1Onu
C05NkGnnvQ2QCaodVqym12UQvY2QwbTZo8/T5mzc20WZvTq3bFYg+ZJnik0mNEVhUuqqZQJhRc8T
QQibIuTBUODMHYiNIYlJybLYiCzY7QcjGclDLEqQmWOZMebgpcYrNYlDQkYoKOJkZmpk7JxVScBx
23aVF3udkJhmIAo4ubFSpQxbujo5LncxdzJTstbuC9mtXNHE1a/E9ycPJSohlW3S29sy6Z6NNXsy
udO/ThwmiGIgohuIaFc4NTIWChU1J4J6ljt22O6phKyvXbnkqVgq1MDjmaGJA4kteTxjfQkOeNKN
7yd6QhhsWGO8sCZdSpSmcTAzMxRpczQjoSNTIjtMpRHi82Liw7X5KZ2qudF63Nxd6nWUiNVzVk4H
F9m7J0MVN1rFxZHFa5M17wXOTJqtasDI605dbkwqcABL6a2yqKMHBoujvFR14P2jDWLrEWvetXpS
qEcTs7jgoIui+DNtISSA1GbnBnQNtSCpQsaQtyPDS5Ij2gCyscl/FvrgmZFyhUgal0JHNtmxGcck
cXiMcS5VFx0LES0YVvsW2omJxpEfStcrXrUPFLyc47SJGsqGW02dodEbXubFTJi2L3Tu8Pf7ezNc
4LJa4pRhec0Ck5o4soQQOp+sQmxWGN5oNDp4NV6mRzLW7u1tNMzOMXtWtMqyQi7EzzvOr3IjRPWD
JkxXMKwgmtNWvitllLGXZmyO5hczYt5LmroNjNnyhBk8TfiCma88HJcyVWpqI1W1JdWYsV7NqtzW
6BLacl6mjvbueBk5rbGmn3rWq9XDJWrZowWODnnycFLFwkzegtNyBsaFSxYsW2MCYQJjhxcUiWIm
ZqZlQNwNZiLznRCxCmttcOU+t/zyejuC2ueY9MBshVKhXcWQ7QspFtkDgiLC7wgdYEFv4yrbbGMG
9PRPQQflRI0vzIPb/kQIMSEIYpd1gNBEqYEPoQgEkzD8P5/sZpzHd1QQoabTaBnIgcNoGDYx/woI
UD84RCBjIG2k0m24QRDbbY2HLho8RJptNptNptNpjGNJENuf09I0XrA+tFVEdYfihYthnC2FtVQ0
h6TjKlsB4jRVXegsUBhLZT8yIb0EAPf9piYh9B8fj/uEyH6bWaF7/2f4uO18rnDpYKpIqqVVKIm0
mkz7T/tW4/81mpFHUCnuP0kyXKhLjoH+BxtWpg6IdEVjDo/pbT9squN/61zIcztMMDu/3/l3HHBo
uHr+1Xv1Av/9+eQ/XuuwkKwao8k4GMvuSTiqzP30QtwlyZTFN/M83BSgtGbzswSUtOiBn+6YX81i
ve9eOq/ydl3mqL4X2F022QwkkQ0FG4rA3w3EbWL9O3gRAiqvJeHBQQkmWvN5wCAizAK/biEGFx3s
WBBgQbsp2qtmsQXYXZcLuC2a+KHubde2lvlkxjlUV52Q7Ql8R4A635YvpYm0apCG04gQOlfGqD4r
bXpwSJ17u93T27ORB3JE6wGG1nhTwORzD2g1TxB8NJJxGBoYaRWVKYeOu2QnAvkl6oPQUq4j1SV+
JoVPCOmAiQLCJI9sKJxfSHhWkfD+2gsL6mDbbY22mxttAFw/xxIvT7P6D7D3H2n0DR/xOn8bEALh
UAHH3HwHESQeHwGjTR0Ymy1S5/ExXKWv2ZNGbRvvk/UwcH6zJuueC9u7+DMyXv22li50fsuWOixY
/wegnkVHD4vJ0YtXmz6tk5uv9buU0XvzL4/PeYMHb1kDMXjhxVVeIz4bxA4Igg8T5yj9/KoDTvPf
w66zPNwsQDzlSGVCnUd8xXguqquRCDzdI0OYQW/CZcl/5CeVVUCH0Fpy8bTL1/GLcHQYHahq9J0H
MynQn0ZBxErIETkaDadpxOZzIE5QQFKwrr4MGD2NGi9c4tW7C1Y2YM1M3JmucGLB+Xol6CBMOJyc
ssqGjW1jyh5+COsMZJNOUwHlx2m7iOEg+yHf5D4unVHKGCT8G0cPjj9MLeH5kJPjqk3wiLCTm9Ds
9i5wdzV0m9tV08OHscGbwepTx8nNxRyYObFgvWqaM1q5q3YN98X39WLNxejNyauaxmxaM2TFupav
dWzZ0ZsZq6NXNa0Xr3u0XtmDQsho0atmC86Pepi8P02czgzavBHzojV7EdngycWanQxHkCg3OIGY
j1XkpqRM8neIuo0kpEYdsUDHd8xil9vkLb4fTZRLvR66zecQOUq2S6ShVPFNn58BzVEJUfBWpo8Q
TrCvSo7FOSJ/QQyBcQwJgln0tDZMwv4PKFZBTt2F4Bc9mIwerf3HoTNHtYLH3num8QPctaOLF7Xz
sFzJezcFjVm6oNF71eJy5dERxcXB9O7aGbvL51JCwso4LFMF78Gbmdl7Z2dTRjirquXr2oY+JVRe
ZZLJkYmn09ar3NcpQP98PczQqaGpzEMUCYGCAEm5dEBnG6xCn2f84Ig0OtNYh3EfJhYwZz8Gz0Nt
aSIVT4UmMQBNT6MYk/ikmfd8lt7ZEsqRNGAJYdOmgvIk0/bT2+vukzrd4G85dUDTgby8icDuMpMN
LyGM9WTBu2/NhTG+jDumpPLGpZHK9xPtluNBgZiAU7271I7nyZF709MVzRtI4QqJ7IHuQ499Ebwo
ntPNKEvkRzcnJ0ejP+/M9HqAqoQkNpKZRhEU2IaQrMC00DjHFvp+49TE45LplLKsWam5zSSI4W8q
HGkuLyDmmw2EYoChpZMOV8oX8ogadJxlsjo8Xk83N+X/OHzs5thDwdJxAaUMx+rAPT4Ic3r2Jbq1
BQ9gsP4F9wFiIBfcKWVAnVAnIQqQx3KMAr29oHaX8bcECKOHAmKKxUZBghUqJUbvkfW+/v+++lMx
TcEQQjj4kK5Zcuam1aVnXAhR4xCgwhhgR+2D0kW1ECxK/mVSK30XJVPhxdNiSMm0CXQR7QXCDkF5
M82oYJsCHCQ0R8s/N1qjxZBolqdCQmORyJnTyNO/veeJA9J6j1GcmGHI9a1ybbZuT0WOUyZmSuau
SnaS9ite5iXzBA1LlyRsYCkDMqc6mRcveY4qRT3wVFeanhLX4az/jrt9urrIOqvFXe71PB4HcxaQ
L6qJ7HwPbxVcoeB/IBp84DAj0qwXvmRDun7vgRBkcRuKkbbiShr2QRGpSYdRu6EOqWJvQ7RMU6Lh
L1TFWJRfu2iYCZHLhG9o9rsPOJ7mEyD+hDRnErDrA3bTq1G2cLDAs0ICVes1ecSvAQD7JUg1t4lx
MZm2KDIDTB/5ShV2clCA2Q+9T7JXInnkqp1rTx0g8wNockAQq67QTYRhVLzob74hUA+wFDkepDyS
xS0Q1r2BFPcxCMEBHXw1aDvkxoEstEDZfjzB47qTMophm9BRBDTCB6q7BDhaoOoa8u2XyqJDxV5r
vLNQNQapMjAI+1NcQr3oYkK0Lb4RgWBBIC/d3kYRG5EOapDDjdeIgKKKfL3HxJIY8Z90sojmkoby
BfYJWJ8J9fByIhsEo3m9tsN/R80hOuQA419kGcsUr31mqbsUSpSZNHCNifa+s5w232Fld9PGYO2k
fflRD5T8Uxa4ScbHr5vRUiUkUJRQm6WTe3XwsXOsK0uzh1QkQS4sjwIRq26czZ5aWx4E+2iGCudH
J6TH1RDctv7t+/zcdeM8HrbCWk9iOs8AlTeXy+kZspC3ty9Le3WBjv9EPhCxC3WDG5kQuAcGFDUh
ep8iATLuZ+XhSlIGOdkiqa23UtillFkh2H0eiMcC+EKfqFSGPOB735LuML3mVZUiPPVeLdPXUMsz
EdG071LUQDNVyXLaOMqQ4OvPXV2HFdf7FI/fZvJzCSMhtoJKDg2dQBoaKQEJMaS/lIggkCxAKwgO
Q6OFEA9KG3nMy9LOHfFucrTXLF1IgFD6Mk25kBdaE0ZO04rdA4fKDssnJcuGBrAlq50kEj9HCNBo
G02DLCikdaFS0oEi88MCL3F2BAIawZn4bUMSlXCjKQVKJkUoKT0K/GEmNQL2IQEFYfVHFa7Tk0Tc
b22G2KCh6jVyG53YPS84UnmQ873M8N2sgVhU460K0O0RKH43IBnyufL1H46IfWjhzrjosMEXQ65r
74hkTkJSN0EyHRnAOzQhoEIE7MqLbZBjhYhako29PqieM+7tMoh3iDOdvIn1FFu2CywSGIQggIlv
k7KSh8dgMjy6WQlSiYIZ1+CEC00IYIkl5XINoMHLQ5HT87QC6kXxA9cjy86Z6ISZTCYu09fpD8kM
BNIUizUuLuaXTqJZOtTqFJ2Y9CJM83D6LWSkXcIhsnxsfCVLKUKE+vRNa+KiwikKog0DmRUBUhIX
1kfdaBntt32ERXxHH64KuiKSywvoSwJ960f09ksvD4BKCC4dftdgWIVCFQrohs90+CNDpa2ttntr
yWHmlHJXD8cvgXkO7g4HfIkXCZO9fPRzRHfz5bzjmYCu7dJLD/yHJ9FSqe9ZBSSwpYVYpAOEyAcD
IBwmQDhMgHCZCGQmQUqI8Ijp3by1M2lLIU0zkR8ZfIz0q+JVyI8E8+pGi8IpIQUmUG8x1YPskQhw
fgo0CkpWjEMAW7iilUUlJEAtkzo/McImYXekPGG6G1LoTASpQmqeZ2nwnGR2tNIRPcJchLhIxqct
cnYhGRdJiFGaGVZg17l6O+oY37IafkvQs6pjRK0+2Iffm+TauLU5yNumKGhRLVGx8TKmToaW690Y
pIfSg0WhllNRUlfYhAGy2YlPq1VBB1YhEgakIO1N3yViHNI0EDz9hxWeXa7L3cb7hLE9VHnEFtTh
74fYj7mn73I9QbHunl9Op1LD8M8xTfUzErf4xEBt6wkPX4vIAOys34zdkUbvZEV6bCyfchCinPuO
bgPHFab16NgHuRDjziYzdPlPZcJTxEQFDA6wonoOS+TATPzOiRzaDJ3NQGkex747crLSklVbvxOk
+dfrDmOCM5d72N8IfDqE1A6m8TYguMMgoZtDZilHNNCRuRciyi2Fj4o81x5KkncErGGMNHr6XXPl
Jmw15uk35ou9DVH1Q97nR80QK+dFiFyHo2oSxA1vMo8eSiGMPDEHAYJ1f1RkLL63/4u5IpwoSFe5
apcA

Reply via email to