diff -urN v2.6.5/linux/include/linux/netfilter_ipv4/ip_nat.h linux/include/linux/netfilter_ipv4/ip_nat.h --- v2.6.5/linux/include/linux/netfilter_ipv4/ip_nat.h 2004-03-11 23:48:04.000000000 +0200 +++ linux/include/linux/netfilter_ipv4/ip_nat.h 2004-04-14 11:06:52.257017720 +0300 @@ -121,5 +121,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.6.5/linux/include/net/ip_vs.h linux/include/net/ip_vs.h --- v2.6.5/linux/include/net/ip_vs.h 2004-03-11 23:48:07.000000000 +0200 +++ linux/include/net/ip_vs.h 2004-04-14 11:06:52.259017416 +0300 @@ -358,6 +358,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 }; @@ -714,6 +716,16 @@ */ /* + * Netfilter connection tracking + * (from ip_vs_nfct.c) + */ +extern int ip_vs_nfct_confirm(struct sk_buff *skb, struct ip_vs_conn *cp); +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 @@ -881,8 +893,20 @@ extern int sysctl_ip_vs_expire_nodest_conn; extern int sysctl_ip_vs_sync_threshold[2]; 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.6.5/linux/net/ipv4/ipvs/Kconfig linux/net/ipv4/ipvs/Kconfig --- v2.6.5/linux/net/ipv4/ipvs/Kconfig 2004-04-04 09:43:37.000000000 +0300 +++ linux/net/ipv4/ipvs/Kconfig 2004-04-14 11:06:52.260017264 +0300 @@ -241,4 +241,12 @@ If you want to compile it in kernel, say Y. To compile it as a module, choose M here. If unsure, say N. +config IP_VS_NFCT + bool "Netfilter connection tracking" + depends on IP_VS && IP_NF_CONNTRACK + ---help--- + The Netfilter connection tracking support allows the IPVS + connection state to be exported to the Netfilter framework + for filtering purposes. + endmenu diff -urN v2.6.5/linux/net/ipv4/ipvs/Makefile linux/net/ipv4/ipvs/Makefile --- v2.6.5/linux/net/ipv4/ipvs/Makefile 2004-03-11 23:48:16.000000000 +0200 +++ linux/net/ipv4/ipvs/Makefile 2004-04-14 11:06:52.260017264 +0300 @@ -9,10 +9,13 @@ ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_ESP) += ip_vs_proto_esp.o ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_AH) += ip_vs_proto_ah.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_xmit.o ip_vs_app.o ip_vs_sync.o \ ip_vs_est.o ip_vs_proto.o ip_vs_proto_icmp.o \ - $(ip_vs_proto-objs-y) + $(ip_vs_proto-objs-y) $(ip_vs-extra_objs-y) # IPVS core diff -urN v2.6.5/linux/net/ipv4/ipvs/ip_vs_conn.c linux/net/ipv4/ipvs/ip_vs_conn.c --- v2.6.5/linux/net/ipv4/ipvs/ip_vs_conn.c 2004-04-04 09:43:37.000000000 +0300 +++ linux/net/ipv4/ipvs/ip_vs_conn.c 2004-04-14 11:06:52.261017112 +0300 @@ -519,6 +519,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 + if (unlikely(cp->app != NULL)) ip_vs_unbind_app(cp); ip_vs_unbind_dest(cp); diff -urN v2.6.5/linux/net/ipv4/ipvs/ip_vs_core.c linux/net/ipv4/ipvs/ip_vs_core.c --- v2.6.5/linux/net/ipv4/ipvs/ip_vs_core.c 2004-03-11 23:48:16.000000000 +0200 +++ linux/net/ipv4/ipvs/ip_vs_core.c 2004-04-14 11:06:52.262016960 +0300 @@ -698,6 +698,8 @@ skb->nfcache |= NFC_IPVS_PROPERTY; verdict = NF_ACCEPT; + if (sysctl_ip_vs_snat_reroute && ip_route_me_harder(pskb)) + verdict = NF_DROP; out: __ip_vs_conn_put(cp); @@ -814,6 +816,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(pskb)) + goto drop; + LeaveFunction(11); return NF_ACCEPT; diff -urN v2.6.5/linux/net/ipv4/ipvs/ip_vs_ctl.c linux/net/ipv4/ipvs/ip_vs_ctl.c --- v2.6.5/linux/net/ipv4/ipvs/ip_vs_ctl.c 2004-04-04 09:43:37.000000000 +0300 +++ linux/net/ipv4/ipvs/ip_vs_ctl.c 2004-04-14 11:06:52.264016656 +0300 @@ -77,6 +77,10 @@ int sysctl_ip_vs_expire_nodest_conn = 0; int sysctl_ip_vs_sync_threshold[2] = { 3, 50 }; 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 @@ -1419,6 +1423,16 @@ .mode = 0644, .proc_handler = &proc_dointvec, }, +#ifdef CONFIG_IP_VS_NFCT + { + .ctl_name = NET_IPV4_VS_CONNTRACK, + .procname = "conntrack", + .data = &sysctl_ip_vs_conntrack, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif { .ctl_name = NET_IPV4_VS_DROP_ENTRY, .procname = "drop_entry", @@ -1443,6 +1457,14 @@ .mode = 0644, .proc_handler = &proc_do_defense_mode, }, + { + .ctl_name = NET_IPV4_VS_SNAT_REROUTE, + .procname = "snat_reroute", + .data = &sysctl_ip_vs_snat_reroute, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #if 0 { .ctl_name = NET_IPV4_VS_TO_ES, diff -urN v2.6.5/linux/net/ipv4/ipvs/ip_vs_ftp.c linux/net/ipv4/ipvs/ip_vs_ftp.c --- v2.6.5/linux/net/ipv4/ipvs/ip_vs_ftp.c 2004-03-11 23:48:16.000000000 +0200 +++ linux/net/ipv4/ipvs/ip_vs_ftp.c 2004-04-14 11:06:52.265016504 +0300 @@ -199,6 +199,11 @@ ip_vs_control_add(n_cp, cp); } +#ifdef CONFIG_IP_VS_NFCT + if ((*pskb)->nfct) + ip_vs_nfct_expect_related(*pskb, n_cp, 0, IPPROTO_TCP, 0); +#endif + /* * Replace the old passive address with the new one */ @@ -331,6 +336,11 @@ ip_vs_control_add(n_cp, cp); } +#ifdef CONFIG_IP_VS_NFCT + if ((*pskb)->nfct) + ip_vs_nfct_expect_related(*pskb, n_cp, n_cp->dport, IPPROTO_TCP, 1); +#endif + /* * Move tunnel to listen state */ diff -urN v2.6.5/linux/net/ipv4/ipvs/ip_vs_nfct.c linux/net/ipv4/ipvs/ip_vs_nfct.c --- v2.6.5/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-14 11:06:52.267016200 +0300 @@ -0,0 +1,388 @@ +/* + * 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 + * Julian Anastasov 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) +#include +#include +#include +#ifdef CONFIG_IP_NF_NAT_NEEDED +#include +#endif +#endif + +#include + + +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) +{ + /* + * 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; + __u16 ports[2]; +#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; + + if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, ports, sizeof(ports)) < 0) + return NF_DROP; + + 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 = ports[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) +{ + 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_TCP_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) : 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.6.5/linux/net/ipv4/ipvs/ip_vs_xmit.c linux/net/ipv4/ipvs/ip_vs_xmit.c --- v2.6.5/linux/net/ipv4/ipvs/ip_vs_xmit.c 2004-03-11 23:48:16.000000000 +0200 +++ linux/net/ipv4/ipvs/ip_vs_xmit.c 2004-04-14 11:14:43.442386656 +0300 @@ -198,6 +198,19 @@ dst_release(skb->dst); skb->dst = &rt->u.dst; +#ifdef CONFIG_IP_VS_NFCT + if (ip_vs_use_conntrack(skb)) { + int verdict; + + verdict = ip_vs_nfct_confirm(skb, cp); + + if (verdict == NF_STOLEN) + goto tx_error_out; + if (verdict != NF_ACCEPT) + goto tx_error; + } +#endif + /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -213,6 +226,7 @@ dst_link_failure(skb); tx_error: kfree_skb(skb); + tx_error_out: LeaveFunction(10); return NF_STOLEN; } @@ -264,6 +278,19 @@ dst_release(skb->dst); skb->dst = &rt->u.dst; +#ifdef CONFIG_IP_VS_NFCT + if (ip_vs_use_conntrack(skb)) { + int verdict; + + verdict = ip_vs_nfct_confirm(skb, cp); + + if (verdict == NF_STOLEN) + goto tx_error_out; + if (verdict != NF_ACCEPT) + goto tx_error; + } +#endif + /* mangle the packet */ if (pp->dnat_handler && !pp->dnat_handler(&skb, pp, cp)) goto tx_error; @@ -290,8 +317,9 @@ tx_error_icmp: dst_link_failure(skb); tx_error: - LeaveFunction(10); kfree_skb(skb); + tx_error_out: + LeaveFunction(10); return NF_STOLEN; tx_error_put: ip_rt_put(rt); @@ -389,13 +417,26 @@ /* fix old IP header checksum */ ip_send_check(old_iph); - skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); - memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); - /* drop old route */ dst_release(skb->dst); skb->dst = &rt->u.dst; +#ifdef CONFIG_IP_VS_NFCT + if (ip_vs_use_conntrack(skb)) { + int verdict; + + verdict = ip_vs_nfct_confirm(skb, cp); + + if (verdict == NF_STOLEN) + goto tx_error_out; + if (verdict != NF_ACCEPT) + goto tx_error; + } +#endif + + skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + /* * Push down and install the IPIP header. */ @@ -431,6 +472,7 @@ dst_link_failure(skb); tx_error: kfree_skb(skb); + tx_error_out: LeaveFunction(10); return NF_STOLEN; } @@ -476,6 +518,19 @@ dst_release(skb->dst); skb->dst = &rt->u.dst; +#ifdef CONFIG_IP_VS_NFCT + if (ip_vs_use_conntrack(skb)) { + int verdict; + + verdict = ip_vs_nfct_confirm(skb, cp); + + if (verdict == NF_STOLEN) + goto tx_error_out; + if (verdict != NF_ACCEPT) + goto tx_error; + } +#endif + /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; @@ -491,6 +546,7 @@ dst_link_failure(skb); tx_error: kfree_skb(skb); + tx_error_out: LeaveFunction(10); return NF_STOLEN; } diff -urN v2.6.5/linux/net/ipv4/netfilter/ip_conntrack_standalone.c linux/net/ipv4/netfilter/ip_conntrack_standalone.c --- v2.6.5/linux/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-11 23:48:17.000000000 +0200 +++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-04-14 11:06:52.267016200 +0300 @@ -580,6 +580,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.6.5/linux/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c --- v2.6.5/linux/net/ipv4/netfilter/ip_nat_core.c 2004-02-19 00:13:38.000000000 +0200 +++ linux/net/ipv4/netfilter/ip_nat_core.c 2004-04-14 11:06:52.268016048 +0300 @@ -715,6 +715,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); +} + /* Returns true if succeeded. */ static int manip_pkt(u_int16_t proto, diff -urN v2.6.5/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c --- v2.6.5/linux/net/ipv4/netfilter/ip_nat_standalone.c 2004-04-04 09:43:37.000000000 +0300 +++ linux/net/ipv4/netfilter/ip_nat_standalone.c 2004-04-14 11:06:52.269015896 +0300 @@ -389,5 +389,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");