diff -urN v2.4.26/linux/include/linux/netfilter_ipv4/ip_nat.h linux/include/linux/netfilter_ipv4/ip_nat.h
--- v2.4.26/linux/include/linux/netfilter_ipv4/ip_nat.h	2004-04-14 23:14:10.000000000 +0300
+++ linux/include/linux/netfilter_ipv4/ip_nat.h	2004-04-17 17:55:18.435437640 +0300
@@ -126,5 +126,9 @@
 extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
 				    u_int32_t newval,
 				    u_int16_t oldcheck);
+
+extern void ip_nat_replace_in_hashes(struct ip_conntrack *conntrack,
+				     struct ip_nat_info *info);
+
 #endif /*__KERNEL__*/
 #endif
diff -urN v2.4.26/linux/include/net/ip_vs.h linux/include/net/ip_vs.h
--- v2.4.26/linux/include/net/ip_vs.h	2004-04-14 23:14:11.000000000 +0300
+++ linux/include/net/ip_vs.h	2004-04-17 17:55:18.436437488 +0300
@@ -317,6 +317,8 @@
 	NET_IPV4_VS_EXPIRE_NODEST_CONN=23,
 	NET_IPV4_VS_SYNC_THRESHOLD=24,
 	NET_IPV4_VS_NAT_ICMP_SEND=25,
+	NET_IPV4_VS_SNAT_REROUTE=26,
+	NET_IPV4_VS_CONNTRACK=27,
 	NET_IPV4_VS_LAST
 };
 
@@ -562,6 +564,17 @@
  */
 
 /*
+ *      Netfilter connection tracking
+ *      (from ip_vs_nfct.c)
+ */
+extern int ip_vs_nfct_confirm(struct sk_buff *skb, struct ip_vs_conn *cp,
+			      union ip_vs_tphdr h);
+extern void ip_vs_nfct_expect_related(struct sk_buff *skb,
+				      struct ip_vs_conn *cp,
+				      __u16 port, __u16 proto, int from_rs);
+extern void ip_vs_nfct_conn_drop(struct ip_vs_conn *cp);
+
+/*
  *     IPVS connection entry hash table
  */
 #ifndef CONFIG_IP_VS_TAB_BITS
@@ -702,8 +715,20 @@
 extern int sysctl_ip_vs_expire_nodest_conn;
 extern int sysctl_ip_vs_sync_threshold;
 extern int sysctl_ip_vs_nat_icmp_send;
+extern int sysctl_ip_vs_snat_reroute;
 extern struct ip_vs_stats ip_vs_stats;
 
+#ifdef CONFIG_IP_VS_NFCT
+
+extern int sysctl_ip_vs_conntrack;
+
+static inline int ip_vs_use_conntrack(struct sk_buff *skb)
+{
+	return sysctl_ip_vs_conntrack && skb->nfct;
+}
+
+#endif
+
 extern struct ip_vs_service *ip_vs_service_get(__u32 fwmark,
 					       __u16 protocol,
 					       __u32 vaddr, __u16 vport);
diff -urN v2.4.26/linux/net/ipv4/ipvs/Config.in linux/net/ipv4/ipvs/Config.in
--- v2.4.26/linux/net/ipv4/ipvs/Config.in	2004-04-14 23:14:11.000000000 +0300
+++ linux/net/ipv4/ipvs/Config.in	2004-04-17 17:55:18.436437488 +0300
@@ -21,6 +21,7 @@
   dep_tristate '  never queue scheduling' CONFIG_IP_VS_NQ $CONFIG_IP_VS
   comment 'IPVS application helper'
   dep_tristate '  FTP protocol helper' CONFIG_IP_VS_FTP $CONFIG_IP_VS
+  dep_mbool '  Netfilter connection tracking' CONFIG_IP_VS_NFCT $CONFIG_IP_VS $CONFIG_IP_NF_CONNTRACK
 fi
 
 endmenu
diff -urN v2.4.26/linux/net/ipv4/ipvs/Makefile linux/net/ipv4/ipvs/Makefile
--- v2.4.26/linux/net/ipv4/ipvs/Makefile	2003-11-28 22:04:14.000000000 +0200
+++ linux/net/ipv4/ipvs/Makefile	2004-04-17 17:55:18.444436272 +0300
@@ -11,8 +11,15 @@
 
 export-objs :=	ip_vs_core.o ip_vs_app.o
 
+ip_vs-extra_objs-y :=
+ip_vs-extra_objs-$(CONFIG_IP_VS_NFCT) += ip_vs_nfct.o
+
 ip_vs-objs :=	ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \
-		ip_vs_app.o ip_vs_sync.o ip_vs_est.o
+		ip_vs_app.o ip_vs_sync.o ip_vs_est.o \
+		$(ip_vs-extra_objs-y)
+ifeq ($(CONFIG_IP_VS_NFCT),y)
+export-objs += ip_vs_nfct.o
+endif
 
 ifeq ($(CONFIG_IP_VS),y)
   obj-y := $(ip_vs-objs)
diff -urN v2.4.26/linux/net/ipv4/ipvs/ip_vs_conn.c linux/net/ipv4/ipvs/ip_vs_conn.c
--- v2.4.26/linux/net/ipv4/ipvs/ip_vs_conn.c	2004-04-14 23:14:11.000000000 +0300
+++ linux/net/ipv4/ipvs/ip_vs_conn.c	2004-04-17 17:55:18.438437184 +0300
@@ -635,6 +635,21 @@
 		}
 	}
 
+#ifdef CONFIG_IP_VS_NFCT
+	if (ip_vs_use_conntrack(skb)) {
+		union ip_vs_tphdr h;
+		int verdict;
+
+		h.raw = skb->nh.raw + skb->nh.iph->ihl * 4;
+		verdict = ip_vs_nfct_confirm(skb, cp, h);
+
+		if (verdict != NF_ACCEPT) {
+			ip_rt_put(rt);
+			goto tx_error;
+		}
+	}
+#endif
+
 	/* drop old route */
 	dst_release(skb->dst);
 	skb->dst = &rt->u.dst;
@@ -758,6 +773,16 @@
 	if (ip_vs_skb_cow(skb, rt->u.dst.dev->hard_header_len, &iph, &h.raw))
 		return NF_DROP;
 
+#ifdef CONFIG_IP_VS_NFCT
+	/* Confirm the conn before the app handlers, useful for UDP apps */
+	if (ip_vs_use_conntrack(skb)) {
+		int verdict = ip_vs_nfct_confirm(skb, cp, h);
+
+		if (verdict != NF_ACCEPT)
+			return verdict;
+	}
+#endif
+
 	/* mangle the packet */
 	iph->daddr = cp->daddr;
 	h.portp[1] = cp->dport;
@@ -911,6 +936,21 @@
 		old_iph = skb->nh.iph;
 	}
 
+#ifdef CONFIG_IP_VS_NFCT
+	if (ip_vs_use_conntrack(skb)) {
+		union ip_vs_tphdr h;
+		int verdict;
+
+		h.raw = (char *) old_iph + old_iph->ihl * 4;
+		verdict = ip_vs_nfct_confirm(skb, cp, h);
+
+		if (verdict != NF_ACCEPT) {
+			ip_rt_put(rt);
+			goto tx_error;
+		}
+	}
+#endif
+
 	skb->h.raw = skb->nh.raw;
 	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
@@ -988,6 +1028,21 @@
 		}
 	}
 
+#ifdef CONFIG_IP_VS_NFCT
+	if (ip_vs_use_conntrack(skb)) {
+		union ip_vs_tphdr h;
+		int verdict;
+
+		h.raw = skb->nh.raw + skb->nh.iph->ihl * 4;
+		verdict = ip_vs_nfct_confirm(skb, cp, h);
+
+		if (verdict != NF_ACCEPT) {
+			ip_rt_put(rt);
+			goto tx_error;
+		}
+	}
+#endif
+
 	/* drop old route */
 	dst_release(skb->dst);
 	skb->dst = &rt->u.dst;
@@ -1219,6 +1274,11 @@
 		if (cp->control)
 			ip_vs_control_del(cp);
 
+#ifdef CONFIG_IP_VS_NFCT
+		if (sysctl_ip_vs_conntrack)
+			ip_vs_nfct_conn_drop(cp);
+#endif
+
 		ip_vs_unbind_dest(cp);
 		ip_vs_unbind_app(cp);
 		ip_vs_timeout_detach(cp);
diff -urN v2.4.26/linux/net/ipv4/ipvs/ip_vs_core.c linux/net/ipv4/ipvs/ip_vs_core.c
--- v2.4.26/linux/net/ipv4/ipvs/ip_vs_core.c	2003-11-28 22:04:14.000000000 +0200
+++ linux/net/ipv4/ipvs/ip_vs_core.c	2004-04-17 17:55:18.440436880 +0300
@@ -621,6 +621,9 @@
 
 	skb->nfcache |= NFC_IPVS_PROPERTY;
 
+	if (sysctl_ip_vs_snat_reroute && ip_route_me_harder(skb_p))
+		return NF_DROP;
+
 	return NF_ACCEPT;
 }
 
@@ -811,6 +814,25 @@
 
 	skb->nfcache |= NFC_IPVS_PROPERTY;
 
+	/*
+	 * nf_iterate does not expect change in the skb->dst->dev.
+	 * It looks like it is not fatal to enable this code for hooks
+	 * where our handlers are at the end of the chain list and
+	 * when all next handlers use skb->dst->dev and not outdev.
+	 * It will definitely route properly the inout NAT traffic
+	 * when multiple paths are used.
+	 */
+
+	 /* For policy routing, packets originating from this
+	  * machine itself may be routed differently to packets
+	  * passing through.  We want this packet to be routed as
+	  * if it came from this machine itself.  So re-compute
+	  * the routing information.
+	  */
+
+	if (sysctl_ip_vs_snat_reroute && ip_route_me_harder(skb_p))
+		return NF_DROP;
+
 	LeaveFunction(11);
 	return NF_ACCEPT;
 }
diff -urN v2.4.26/linux/net/ipv4/ipvs/ip_vs_ctl.c linux/net/ipv4/ipvs/ip_vs_ctl.c
--- v2.4.26/linux/net/ipv4/ipvs/ip_vs_ctl.c	2004-04-14 23:14:11.000000000 +0300
+++ linux/net/ipv4/ipvs/ip_vs_ctl.c	2004-04-17 17:55:18.442436576 +0300
@@ -76,6 +76,10 @@
 int sysctl_ip_vs_expire_nodest_conn = 0;
 int sysctl_ip_vs_sync_threshold = 3;
 int sysctl_ip_vs_nat_icmp_send = 0;
+int sysctl_ip_vs_snat_reroute = 0;
+#ifdef CONFIG_IP_VS_NFCT
+int sysctl_ip_vs_conntrack = 0;
+#endif
 
 #ifdef CONFIG_IP_VS_DEBUG
 static int sysctl_ip_vs_debug_level = 0;
@@ -1383,6 +1387,11 @@
 	 {NET_IPV4_VS_AMDROPRATE, "am_droprate",
 	  &sysctl_ip_vs_am_droprate, sizeof(int), 0644, NULL,
 	  &proc_dointvec},
+#ifdef CONFIG_IP_VS_NFCT
+	 {NET_IPV4_VS_CONNTRACK, "conntrack",
+	  &sysctl_ip_vs_conntrack, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
+#endif
 	 {NET_IPV4_VS_DROP_ENTRY, "drop_entry",
 	  &sysctl_ip_vs_drop_entry, sizeof(int), 0644, NULL,
 	  &ip_vs_sysctl_defense_mode},
@@ -1392,6 +1401,9 @@
 	 {NET_IPV4_VS_SECURE_TCP, "secure_tcp",
 	  &sysctl_ip_vs_secure_tcp, sizeof(int), 0644, NULL,
 	  &ip_vs_sysctl_defense_mode},
+	 {NET_IPV4_VS_SNAT_REROUTE, "snat_reroute",
+	  &sysctl_ip_vs_snat_reroute, sizeof(int), 0644, NULL,
+	  &proc_dointvec},
 	 {NET_IPV4_VS_TO_ES, "timeout_established",
 	  &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED],
 	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
diff -urN v2.4.26/linux/net/ipv4/ipvs/ip_vs_ftp.c linux/net/ipv4/ipvs/ip_vs_ftp.c
--- v2.4.26/linux/net/ipv4/ipvs/ip_vs_ftp.c	2004-04-14 23:14:11.000000000 +0300
+++ linux/net/ipv4/ipvs/ip_vs_ftp.c	2004-04-17 17:55:18.443436424 +0300
@@ -198,6 +198,11 @@
 				atomic_inc(&cp->dest->inactconns);
 		}
 
+#ifdef CONFIG_IP_VS_NFCT
+		if (skb->nfct)
+			ip_vs_nfct_expect_related(skb, n_cp, 0, IPPROTO_TCP, 0);
+#endif
+
 		/*
 		 * Replace the old passive address with the new one
 		 */
@@ -324,6 +329,11 @@
 			atomic_inc(&cp->dest->inactconns);
 	}
 
+#ifdef CONFIG_IP_VS_NFCT
+	if (skb->nfct)
+		ip_vs_nfct_expect_related(skb, n_cp, n_cp->dport, IPPROTO_TCP, 1);
+#endif
+
 	/*
 	 *	Move tunnel to listen state
 	 */
diff -urN v2.4.26/linux/net/ipv4/ipvs/ip_vs_nfct.c linux/net/ipv4/ipvs/ip_vs_nfct.c
--- v2.4.26/linux/net/ipv4/ipvs/ip_vs_nfct.c	1970-01-01 02:00:00.000000000 +0200
+++ linux/net/ipv4/ipvs/ip_vs_nfct.c	2004-04-17 17:56:00.719009560 +0300
@@ -0,0 +1,386 @@
+/*
+ * ip_vs_nfct.c:	Netfilter connection tracking support for IPVS
+ *
+ * Portions Copyright (C) 2001-2002
+ * Antefacto Ltd, 181 Parnell St, Dublin 1, Ireland.
+ *
+ * Portions Copyright (C) 2003
+ * Julian Anastasov
+ *
+ *
+ * This code 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-1307  USA
+ *
+ *
+ * Authors:
+ * Ben North <ben@redfrontdoor.org>
+ * Julian Anastasov <ja@ssi.bg>		Reorganize and sync with latest kernels
+ *
+ *
+ * Current status:
+ *
+ * - provide conntrack confirmation for new and related connections, by
+ * this way we can see their proper conntrack state in all hooks
+ * - support for all forwarding methods, not only NAT
+ * - FTP support (NAT), ability to support other NAT apps with expectations
+ * - to correctly create expectations for related NAT connections the proper
+ * NF conntrack support must be already installed, eg. ip_vs_ftp requires
+ * ip_conntrack_ftp for the same ports
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/compiler.h>
+#include <linux/vmalloc.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+#include <linux/netfilter_ipv4/ip_nat.h>
+#endif
+#endif
+
+#include <net/ip_vs.h>
+
+
+EXPORT_SYMBOL(ip_vs_nfct_expect_related);
+
+
+#define FMT_TUPLE	"%u.%u.%u.%u:%u->%u.%u.%u.%u:%u/%u"
+#define ARG_TUPLE(t)	NIPQUAD((t)->src.ip), ntohs((t)->src.u.all), \
+			NIPQUAD((t)->dst.ip), ntohs((t)->dst.u.all), \
+			(t)->dst.protonum
+
+#define FMT_CONN	"%u.%u.%u.%u:%u->%u.%u.%u.%u:%u->%u.%u.%u.%u:%u/%u:%u"
+#define ARG_CONN(c)	NIPQUAD((c)->caddr), ntohs((c)->cport), \
+			NIPQUAD((c)->vaddr), ntohs((c)->vport), \
+			NIPQUAD((c)->daddr), ntohs((c)->dport), \
+			(c)->protocol, (c)->state
+
+static int __ip_vs_nfct_confirm(struct sk_buff *skb, struct ip_vs_conn *cp,
+				union ip_vs_tphdr h)
+{
+	/*
+	 * The assumptions:
+	 * - the nfct is !NULL and is not confirmed
+	 * - we are called before any mangle
+	 */
+
+	struct iphdr *iph = skb->nh.iph;
+	struct ip_conntrack *ct = (struct ip_conntrack *) skb->nfct->master;
+	struct ip_conntrack_tuple new_reply;
+	int ret;
+#ifdef CONFIG_IP_VS_DEBUG
+	struct ip_conntrack_tuple *orig_tup =
+		&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+	struct ip_conntrack_tuple *orig_rep =
+		&ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+	int initialized = ct->nat.info.initialized;
+#else
+	int initialized = 0;
+#endif
+#endif
+
+	IP_VS_DBG(7, "%s: ct=%p, init=%d, tuples=" FMT_TUPLE ", " FMT_TUPLE
+		", cp=" FMT_CONN "\n",
+		__FUNCTION__, ct, initialized,
+		ARG_TUPLE(orig_tup), ARG_TUPLE(orig_rep), ARG_CONN(cp));
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+	/*
+	 * This is really bad, may be we are trying to alter DNAT conn?
+	 * This is not supported, avoid the confirmation.
+	 */
+	if (ct->nat.info.initialized && ct->nat.info.num_manips) {
+#ifdef CONFIG_IP_VS_DEBUG
+		int i;
+
+		IP_VS_DBG(7, "%s: ct=%p, manips=%d, init=%d\n",
+			__FUNCTION__, ct, ct->nat.info.num_manips,
+			ct->nat.info.initialized);
+		for (i = 0; i < ct->nat.info.num_manips; i++) {
+			IP_VS_DBG(7, "%s: ct=%p, manip[%d]: type=%d, hook=%d, dir=%d, to %u.%u.%u.%u:%u\n",
+				__FUNCTION__, ct, i,
+				ct->nat.info.manips[i].maniptype,
+				ct->nat.info.manips[i].hooknum,
+				ct->nat.info.manips[i].direction,
+				NIPQUAD(ct->nat.info.manips[i].manip.ip),
+				ntohs(ct->nat.info.manips[i].manip.u.all));
+		}
+#endif
+		return NF_ACCEPT;
+	}
+#endif
+
+	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
+		goto confirm;
+
+	new_reply.src.ip = cp->daddr;
+	new_reply.src.u.tcp.port = cp->dport;
+	new_reply.dst.ip = iph->saddr;
+	new_reply.dst.u.tcp.port = h.portp[0];
+	new_reply.dst.protonum = iph->protocol;
+
+	ret = ip_conntrack_alter_reply(ct, &new_reply);
+
+	IP_VS_DBG(7, "%s: ct=%p, init=%d, orig=" FMT_TUPLE
+		", new_reply=" FMT_TUPLE " => alter_reply ret=%d\n",
+		__FUNCTION__, ct, initialized,
+		ARG_TUPLE(orig_tup), ARG_TUPLE(&new_reply), ret);
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+	/* Update the NAT hashes if the conntrack has valid NAT info */
+	if (ct->nat.info.initialized)
+		ip_nat_replace_in_hashes(ct, &ct->nat.info);
+#endif
+
+confirm:
+
+	ret = __ip_conntrack_confirm(skb->nfct);
+
+	IP_VS_DBG(7, "%s: ct=%p, init=%d, orig=" FMT_TUPLE " => confirm ret=%d\n",
+		__FUNCTION__, ct, initialized, ARG_TUPLE(orig_tup), ret);
+
+	return ret;
+}
+
+/*
+ * Confirm (and optionally alter) the conntrack entry if needed
+ * because the IPVS packets do not reach ip_confirm.
+ */
+int ip_vs_nfct_confirm(struct sk_buff *skb, struct ip_vs_conn *cp,
+		       union ip_vs_tphdr h)
+{
+	struct iphdr *iph = skb->nh.iph;
+	struct ip_conntrack *ct;
+
+	/* By the time we're sending the packet out the other
+	 * side, there should be a confirmed Netfilter CT entry
+	 * for this connection.  This may not be the case,
+	 * however, if it's a brand new connection, or if the NF
+	 * entry has timed out before ours has.  Either way, if
+	 * the NF CT entry is unconfirmed, confirm it, and deal
+	 * with reply tuple mangling at the same time.
+	 */
+
+	ct = (struct ip_conntrack *) skb->nfct->master;
+
+	/* We only deal with TCP or UDP packets */
+	if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)
+		return NF_ACCEPT;
+
+	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
+		/*
+		 * Do not be surprised if non-NAT conntracks stay in SYN_SENT
+		 * state, may be the replies from the real server go
+		 * directly to client. In any case, keep them in REPLIED
+		 * state (ESTABLISHED).
+		 */
+		if (iph->protocol != IPPROTO_TCP ||
+		    IP_VS_S_ESTABLISHED == cp->state) {
+			set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
+		}
+	}
+
+	/*
+	 * We assume the reused connections do not change their rip:rport
+	 * and we do not need to alter their conntrack reply
+	 */
+	return !is_confirmed(ct) ? __ip_vs_nfct_confirm(skb, cp, h) : NF_ACCEPT;
+}
+
+/*
+ * We are called from init_conntrack() as expectfn handler
+ */
+
+static int ip_vs_nfct_expect_callback(struct ip_conntrack *ct)
+{
+	struct ip_conntrack_tuple *orig, new_reply;
+	struct ip_vs_conn *cp;
+
+	/* 
+	 * - We assume that no NF locks are held before this callback
+	 * - ip_vs_conn_out_get and ip_vs_conn_in_get should match their
+	 * expectations even if they use wildcard values, now we provide
+	 * the actual values from the newly created original conntrack direction
+	 * - We are able to confirm the out->in related connections
+	 * at the usual place (ip_vs_nfct_confirm) but we still have to
+	 * confirm the in->out related connections, so we do it here for
+	 * all kinds of related conns.
+	 */
+
+	/* RS->CLIENT */
+	orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+	cp = ip_vs_conn_out_get(orig->dst.protonum,
+				orig->src.ip, orig->src.u.tcp.port,
+				orig->dst.ip, orig->dst.u.tcp.port);
+	if (cp) {
+		/* Change reply CLIENT->RS to CLIENT->VS */
+		new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+		IP_VS_DBG(7, "%s: ct=%p, tuples=" FMT_TUPLE ", " FMT_TUPLE
+			", found inout cp=" FMT_CONN "\n",
+			__FUNCTION__, ct,
+			ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+			ARG_CONN(cp));
+		new_reply.dst.ip = cp->vaddr;
+		new_reply.dst.u.tcp.port = cp->vport;
+		IP_VS_DBG(7, "%s: ct=%p, new tuples=" FMT_TUPLE ", " FMT_TUPLE
+			", inout cp=" FMT_CONN "\n",
+			__FUNCTION__, ct,
+			ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+			ARG_CONN(cp));
+		goto alter;
+	}
+
+	/* CLIENT->VS */
+	cp = ip_vs_conn_in_get(orig->dst.protonum,
+				orig->src.ip, orig->src.u.tcp.port,
+				orig->dst.ip, orig->dst.u.tcp.port);
+	if (cp) {
+		/* Change reply VS->CLIENT to RS->CLIENT */
+		new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+		IP_VS_DBG(7, "%s: ct=%p, tuples=" FMT_TUPLE ", " FMT_TUPLE
+			", found outin cp=" FMT_CONN "\n",
+			__FUNCTION__, ct,
+			ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+			ARG_CONN(cp));
+		new_reply.src.ip = cp->daddr;
+		new_reply.src.u.tcp.port = cp->dport;
+		IP_VS_DBG(7, "%s: ct=%p, new tuples=" FMT_TUPLE ", " FMT_TUPLE
+			", outin cp=" FMT_CONN "\n",
+			__FUNCTION__, ct,
+			ARG_TUPLE(orig), ARG_TUPLE(&new_reply),
+			ARG_CONN(cp));
+		goto alter;
+	}
+	IP_VS_DBG(7, "%s: ct=%p, tuple=" FMT_TUPLE " - unknown expect\n",
+		__FUNCTION__, ct, ARG_TUPLE(orig));
+	return 0;
+
+alter:
+
+	/* Never alter conntrack for non-NAT conns */
+	if (IP_VS_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ)
+		ip_conntrack_alter_reply(ct, &new_reply);
+	ip_vs_conn_put(cp);
+
+	/* And confirm the connection.	Note that
+	 * __ip_conntrack_confirm() needs a (struct
+	 * nf_ct_info *), and we could probably use
+	 * _ESTABLISHED or _NEW, but for tidiness we use
+	 * the truthful one.
+	 */
+	__ip_conntrack_confirm(&ct->infos[IP_CT_RELATED]);
+
+	return 0;
+}
+
+/*
+ * Create NF conntrack expectation with wildcard (optional) source port.
+ * Then the default callback function will alter the reply and will confirm
+ * the conntrack entry when the first packet comes.
+ */
+void ip_vs_nfct_expect_related(struct sk_buff *skb, struct ip_vs_conn *cp,
+			       __u16 port, __u16 proto, int from_rs)
+{
+	struct ip_conntrack *ct = (struct ip_conntrack *) skb->nfct->master;
+	struct ip_conntrack_expect e = { .expectfn = ip_vs_nfct_expect_callback };
+
+	if (!sysctl_ip_vs_conntrack)
+		return;
+
+	if (!ct->helper) {
+		/* 
+		 * It is a bad idea to create expectation if ct has no helper.
+		 * Please, load the proper conntrack support for cp->vport first.
+		 */
+		IP_VS_DBG(7, "%s: ct=%p, no ct->helper for cp=" FMT_CONN "\n",
+			__FUNCTION__, ct, ARG_CONN(cp));
+		return;
+	}
+
+	if (from_rs) {
+		e.tuple.src.ip = cp->daddr;
+		e.tuple.dst.ip = cp->caddr;
+		e.tuple.dst.u.tcp.port = cp->cport;
+	} else {
+		e.tuple.src.ip = cp->caddr;
+		e.tuple.dst.ip = cp->vaddr;
+		e.tuple.dst.u.tcp.port = cp->vport;
+	}
+	e.tuple.src.u.tcp.port = port;
+	e.tuple.dst.protonum = proto;
+	e.mask.src.ip = 0xffffffff;
+	e.mask.src.u.all = port? 0xffff : 0;
+	e.mask.dst.ip = 0xffffffff;
+	e.mask.dst.u.all = 0xffff;
+	e.mask.dst.protonum = 0xffff;
+
+	IP_VS_DBG(7, "%s: ct=%p, expect tuple=" FMT_TUPLE "\n",
+		__FUNCTION__, ct, ARG_TUPLE(&e.tuple));
+	ip_conntrack_expect_related(ct, &e);
+}
+
+/*
+ * Our connection was terminated, try to drop the conntrack immediately
+ */
+void ip_vs_nfct_conn_drop(struct ip_vs_conn *cp)
+{
+	struct ip_conntrack_tuple_hash *h;
+	struct ip_conntrack *ct;
+	struct ip_conntrack_tuple tuple;
+
+	if (!cp->cport)
+		return;
+
+	tuple.src.ip = cp->caddr;
+	tuple.src.u.all = cp->cport;
+	tuple.dst.ip = cp->vaddr;
+	tuple.dst.u.all = cp->vport;
+	tuple.dst.protonum = cp->protocol;
+
+	IP_VS_DBG(7, "%s: dropping conntrack with tuple=" FMT_TUPLE
+		" for conn " FMT_CONN "\n",
+		__FUNCTION__, ARG_TUPLE(&tuple), ARG_CONN(cp));
+
+	h = ip_conntrack_find_get(&tuple, NULL);
+	if (h) {
+		ct = h->ctrack;
+		if (del_timer(&ct->timeout)) {
+			IP_VS_DBG(7, "%s: ct=%p, deleted conntrack timer for tuple="
+				FMT_TUPLE "\n",
+				__FUNCTION__, ct, ARG_TUPLE(&tuple));
+			if (ct->timeout.function)
+				ct->timeout.function(ct->timeout.data);
+		} else {
+			IP_VS_DBG(7, "%s: ct=%p, no conntrack timer for tuple="
+				FMT_TUPLE "\n",
+				__FUNCTION__, ct, ARG_TUPLE(&tuple));
+		}
+		ip_conntrack_put(ct);
+	} else {
+		IP_VS_DBG(7, "%s: no conntrack for tuple=" FMT_TUPLE "\n",
+			__FUNCTION__, ARG_TUPLE(&tuple));
+	}
+}
+
diff -urN v2.4.26/linux/net/ipv4/netfilter/ip_conntrack_standalone.c linux/net/ipv4/netfilter/ip_conntrack_standalone.c
--- v2.4.26/linux/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-02-19 00:23:39.000000000 +0200
+++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c	2004-04-17 17:55:18.445436120 +0300
@@ -461,6 +461,7 @@
 EXPORT_SYMBOL(ip_conntrack_protocol_register);
 EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
 EXPORT_SYMBOL(invert_tuplepr);
+EXPORT_SYMBOL(__ip_conntrack_confirm);
 EXPORT_SYMBOL(ip_conntrack_alter_reply);
 EXPORT_SYMBOL(ip_conntrack_destroyed);
 EXPORT_SYMBOL(ip_conntrack_get);
diff -urN v2.4.26/linux/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
--- v2.4.26/linux/net/ipv4/netfilter/ip_nat_core.c	2004-02-19 00:23:39.000000000 +0200
+++ linux/net/ipv4/netfilter/ip_nat_core.c	2004-04-17 17:55:18.446435968 +0300
@@ -707,6 +707,17 @@
 	list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
 }
 
+void ip_nat_replace_in_hashes(struct ip_conntrack *conntrack,
+			      struct ip_nat_info *info)
+{
+	WRITE_LOCK(&ip_nat_lock);
+	if (!info->initialized)
+		place_in_hashes(conntrack, info);
+	else
+		replace_in_hashes(conntrack, info);
+	WRITE_UNLOCK(&ip_nat_lock);
+}
+
 static void
 manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len,
 	  const struct ip_conntrack_manip *manip,
diff -urN v2.4.26/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
--- v2.4.26/linux/net/ipv4/netfilter/ip_nat_standalone.c	2004-04-14 23:14:11.000000000 +0300
+++ linux/net/ipv4/netfilter/ip_nat_standalone.c	2004-04-17 17:55:18.465433080 +0300
@@ -360,5 +360,6 @@
 EXPORT_SYMBOL(ip_nat_cheat_check);
 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
 EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
+EXPORT_SYMBOL(ip_nat_replace_in_hashes);
 EXPORT_SYMBOL(ip_nat_used_tuple);
 MODULE_LICENSE("GPL");
