diff -urp v2.6.24/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt
--- v2.6.24/linux/Documentation/filesystems/proc.txt	2008-01-25 10:44:55.000000000 +0200
+++ linux/Documentation/filesystems/proc.txt	2008-01-27 15:20:19.000000000 +0200
@@ -1826,6 +1826,18 @@ the net,  it  will  prevent  spoofing  a
 (external addresses  can  still  be  spoofed), without the need for additional
 firewall rules.
 
+forward_shared
+--------------
+
+Integer  value determines  if a source  validation should  allow forwarding of
+packets  with local source  address. 1 means  yes, 0 means  no. By default the
+flag is disabled and such packets are not forwarded.
+
+If  you enable this flag on internal  network, the router will forward packets
+from  internal hosts with shared  IP addresses no matter  how the rp_filter is
+set.  This flag  is activated only  if it  is enabled both  in specific device
+section and in "all" section.
+
 secure_redirects
 ----------------
 
diff -urp v2.6.24/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.6.24/linux/Documentation/networking/ip-sysctl.txt	2008-01-25 10:44:55.000000000 +0200
+++ linux/Documentation/networking/ip-sysctl.txt	2008-01-27 15:20:19.000000000 +0200
@@ -600,6 +600,17 @@ accept_redirects - BOOLEAN
 forwarding - BOOLEAN
 	Enable IP forwarding on this interface.
 
+forward_shared - BOOLEAN
+	Integer value determines if a source validation should allow
+	forwarding of packets with local source address. 1 means yes,
+	0 means no. By default the flag is disabled and such packets
+	are not forwarded.
+ 
+	If you enable this flag on internal network, the router will forward
+	packets from internal hosts with shared IP addresses no matter how
+	the rp_filter is set. This flag is activated only if it is
+	enabled both in specific device section and in "all" section.
+
 mc_forwarding - BOOLEAN
 	Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
 	and a multicast routing daemon is required.
diff -urp v2.6.24/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.6.24/linux/include/linux/inetdevice.h	2007-07-10 09:18:42.000000000 +0300
+++ linux/include/linux/inetdevice.h	2008-01-27 15:20:19.000000000 +0200
@@ -108,6 +108,8 @@ static inline void ipv4_devconf_setall(s
 #define IN_DEV_ARP_ANNOUNCE(in_dev)	IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE)
 #define IN_DEV_ARP_IGNORE(in_dev)	IN_DEV_MAXCONF((in_dev), ARP_IGNORE)
 
+#define IN_DEV_FORWARD_SHARED(in_dev)	IN_DEV_ANDCONF((in_dev), FORWARD_SHARED)
+
 struct in_ifaddr
 {
 	struct in_ifaddr	*ifa_next;
diff -urp v2.6.24/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.6.24/linux/include/linux/sysctl.h	2008-01-25 10:45:05.000000000 +0200
+++ linux/include/linux/sysctl.h	2008-01-27 15:20:19.000000000 +0200
@@ -491,6 +491,7 @@ enum
 	NET_IPV4_CONF_ARP_IGNORE=19,
 	NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
 	NET_IPV4_CONF_ARP_ACCEPT=21,
+	NET_IPV4_CONF_FORWARD_SHARED=22,
 	__NET_IPV4_CONF_MAX
 };
 
diff -urp v2.6.24/linux/include/net/ip_fib.h linux/include/net/ip_fib.h
--- v2.6.24/linux/include/net/ip_fib.h	2008-01-25 10:45:05.000000000 +0200
+++ linux/include/net/ip_fib.h	2008-01-27 15:20:19.000000000 +0200
@@ -206,7 +206,7 @@ extern void fib_select_default(const str
 extern const struct nla_policy rtm_ipv4_policy[];
 extern void		ip_fib_init(void);
 extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
-			       struct net_device *dev, __be32 *spec_dst, u32 *itag);
+			       struct net_device *dev, __be32 *spec_dst, u32 *itag, int our);
 extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res);
 
 struct rtentry;
diff -urp v2.6.24/linux/kernel/sysctl_check.c linux/kernel/sysctl_check.c
--- v2.6.24/linux/kernel/sysctl_check.c	2008-01-25 10:45:06.000000000 +0200
+++ linux/kernel/sysctl_check.c	2008-02-05 01:05:10.000000000 +0200
@@ -224,6 +224,7 @@ static struct trans_ctl_table trans_net_
 	{ NET_IPV4_CONF_ARP_IGNORE,		"arp_ignore" },
 	{ NET_IPV4_CONF_PROMOTE_SECONDARIES,	"promote_secondaries" },
 	{ NET_IPV4_CONF_ARP_ACCEPT,		"arp_accept" },
+	{ NET_IPV4_CONF_FORWARD_SHARED,		"forward_shared" },
 	{}
 };
 
diff -urp v2.6.24/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.6.24/linux/net/ipv4/devinet.c	2008-01-25 10:45:06.000000000 +0200
+++ linux/net/ipv4/devinet.c	2008-01-27 15:20:19.000000000 +0200
@@ -1447,6 +1447,7 @@ static struct devinet_sysctl_table {
 		DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
 		DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
 		DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
+		DEVINET_SYSCTL_RW_ENTRY(FORWARD_SHARED, "forward_shared"),
 
 		DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
 		DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
diff -urp v2.6.24/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.6.24/linux/net/ipv4/fib_frontend.c	2008-01-25 10:45:06.000000000 +0200
+++ linux/net/ipv4/fib_frontend.c	2008-01-27 15:26:00.000000000 +0200
@@ -191,7 +191,7 @@ unsigned inet_addr_type(__be32 addr)
  */
 
 int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
-			struct net_device *dev, __be32 *spec_dst, u32 *itag)
+			struct net_device *dev, __be32 *spec_dst, u32 *itag, int our)
 {
 	struct in_device *in_dev;
 	struct flowi fl = { .nl_u = { .ip4_u =
@@ -202,6 +202,7 @@ int fib_validate_source(__be32 src, __be
 	struct fib_result res;
 	int no_addr, rpf;
 	int ret;
+	int fwdsh = 0;
 
 	no_addr = rpf = 0;
 	rcu_read_lock();
@@ -209,6 +210,7 @@ int fib_validate_source(__be32 src, __be
 	if (in_dev) {
 		no_addr = in_dev->ifa_list == NULL;
 		rpf = IN_DEV_RPFILTER(in_dev);
+		fwdsh = IN_DEV_FORWARD_SHARED(in_dev);
 	}
 	rcu_read_unlock();
 
@@ -217,7 +219,12 @@ int fib_validate_source(__be32 src, __be
 
 	if (fib_lookup(&fl, &res))
 		goto last_resort;
-	if (res.type != RTN_UNICAST)
+	if (fwdsh) {
+		fwdsh = (res.type == RTN_LOCAL && !our);
+		if (fwdsh)
+			rpf = 0;
+	}
+	if (res.type != RTN_UNICAST && !fwdsh)
 		goto e_inval_res;
 	*spec_dst = FIB_RES_PREFSRC(res);
 	fib_combine_itag(itag, &res);
@@ -237,6 +244,8 @@ int fib_validate_source(__be32 src, __be
 	if (rpf)
 		goto e_inval;
 	fl.oif = dev->ifindex;
+	if (fwdsh)
+		fl.iif = init_net.loopback_dev->ifindex;
 
 	ret = 0;
 	if (fib_lookup(&fl, &res) == 0) {
diff -urp v2.6.24/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.6.24/linux/net/ipv4/route.c	2008-01-25 10:45:06.000000000 +0200
+++ linux/net/ipv4/route.c	2008-01-27 15:21:39.000000000 +0200
@@ -1518,7 +1518,7 @@ static int ip_route_input_mc(struct sk_b
 			goto e_inval;
 		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
 	} else if (fib_validate_source(saddr, 0, tos, 0,
-					dev, &spec_dst, &itag) < 0)
+					dev, &spec_dst, &itag, our) < 0)
 		goto e_inval;
 
 	rth = dst_alloc(&ipv4_dst_ops);
@@ -1631,7 +1631,7 @@ static inline int __mkroute_input(struct
 
 
 	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res),
-				  in_dev->dev, &spec_dst, &itag);
+				  in_dev->dev, &spec_dst, &itag, 0);
 	if (err < 0) {
 		ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,
 					 saddr);
@@ -1800,7 +1800,7 @@ static int ip_route_input_slow(struct sk
 		int result;
 		result = fib_validate_source(saddr, daddr, tos,
 					     init_net.loopback_dev->ifindex,
-					     dev, &spec_dst, &itag);
+					     dev, &spec_dst, &itag, 1);
 		if (result < 0)
 			goto martian_source;
 		if (result)
@@ -1829,7 +1829,7 @@ brd_input:
 		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
 	else {
 		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
-					  &itag);
+					  &itag, 1);
 		if (err < 0)
 			goto martian_source;
 		if (err)
