--- v2.2.19/linux/include/linux/inetdevice.h~	Wed Dec 13 11:19:12 2000
+++ linux/include/linux/inetdevice.h	Sun Jul  1 14:06:02 2001
@@ -18,6 +18,7 @@
 	int	mc_forwarding;
 	int	hidden;
 	int	arp_filter; 
+	int	forward_shared;
 	void	*sysctl;
 };
 
@@ -55,6 +56,8 @@
 
 #define IN_DEV_ARPFILTER(in_dev)	(ipv4_devconf.arp_filter || \
 					 (in_dev)->cnf.arp_filter)
+
+#define IN_DEV_FORWARD_SHARED(in_dev)	((in_dev)->cnf.forward_shared && ipv4_devconf.forward_shared)
 
 struct in_ifaddr
 {
--- v2.2.19/linux/include/linux/sysctl.h~	Tue Jul  3 00:01:05 2001
+++ linux/include/linux/sysctl.h	Sun Jul  1 14:48:48 2001
@@ -274,7 +274,8 @@
 	NET_IPV4_CONF_BOOTP_RELAY=10,
 	NET_IPV4_CONF_LOG_MARTIANS=11,
 	NET_IPV4_CONF_HIDDEN=12,
-	NET_IPV4_CONF_ARPFILTER=13
+	NET_IPV4_CONF_ARPFILTER=13,
+	NET_IPV4_CONF_FORWARD_SHARED=14,
 };
 
 /* /proc/sys/net/ipv6 */
--- v2.2.19/linux/net/ipv4/devinet.c~	Wed Dec 13 11:19:12 2000
+++ linux/net/ipv4/devinet.c	Sun Jul  1 14:08:42 2001
@@ -925,7 +925,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[14];
+	ctl_table devinet_vars[15];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -970,6 +970,9 @@
          &proc_dointvec},
 	{NET_IPV4_CONF_ARPFILTER, "arp_filter",
          &ipv4_devconf.arp_filter, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_FORWARD_SHARED, "forward_shared",
+         &ipv4_devconf.forward_shared, sizeof(int), 0644, NULL,
          &proc_dointvec},
 	 {0}},
 
--- v2.2.19/linux/include/net/ip_fib.h~	Sat Oct 21 12:10:47 2000
+++ linux/include/net/ip_fib.h	Sun Jul  1 15:16:03 2001
@@ -200,7 +200,7 @@
 extern int inet_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
 extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
 extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
-			       struct device *dev, u32 *spec_dst, u32 *itag);
+			struct device *dev, u32 *spec_dst, u32 *itag, int our);
 extern void fib_select_multipath(const struct rt_key *key, struct fib_result *res);
 
 /* Exported by fib_semantics.c */
--- v2.2.19/linux/net/ipv4/fib_frontend.c~	Sat Oct 21 12:10:47 2000
+++ linux/net/ipv4/fib_frontend.c	Sun Jul  1 14:16:19 2001
@@ -189,11 +189,12 @@
  */
 
 int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
-			struct device *dev, u32 *spec_dst, u32 *itag)
+			struct device *dev, u32 *spec_dst, u32 *itag, int our)
 {
 	struct in_device *in_dev = dev->ip_ptr;
 	struct rt_key key;
 	struct fib_result res;
+	int fwdsh = 0;
 
 	key.dst = src;
 	key.src = dst;
@@ -206,7 +207,9 @@
 		return -EINVAL;
 	if (fib_lookup(&key, &res))
 		goto last_resort;
-	if (res.type != RTN_UNICAST)
+	if (IN_DEV_FORWARD_SHARED(in_dev))
+		fwdsh = (res.type == RTN_LOCAL && !our);
+	if (res.type != RTN_UNICAST && !fwdsh)
 		return -EINVAL;
 	*spec_dst = FIB_RES_PREFSRC(res);
 	if (itag)
@@ -220,9 +223,11 @@
 
 	if (in_dev->ifa_list == NULL)
 		goto last_resort;
-	if (IN_DEV_RPFILTER(in_dev))
+	if (IN_DEV_RPFILTER(in_dev) && !fwdsh)
 		return -EINVAL;
 	key.oif = dev->ifindex;
+	if (fwdsh)
+		key.iif = loopback_dev.ifindex;
 	if (fib_lookup(&key, &res) == 0 && res.type == RTN_UNICAST) {
 		*spec_dst = FIB_RES_PREFSRC(res);
 		return FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
@@ -230,7 +235,7 @@
 	return 0;
 
 last_resort:
-	if (IN_DEV_RPFILTER(in_dev))
+	if (IN_DEV_RPFILTER(in_dev) && !fwdsh)
 		return -EINVAL;
 	*spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
 	*itag = 0;
--- v2.2.19/linux/net/ipv4/route.c~	Tue Jul  3 00:01:05 2001
+++ linux/net/ipv4/route.c	Sun Jul  1 14:48:49 2001
@@ -1037,7 +1037,7 @@
 		if (!LOCAL_MCAST(daddr))
 			return -EINVAL;
 		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
-	} else if (fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag) < 0)
+	} else if (fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag, our) < 0)
 		return -EINVAL;
 
 	rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
@@ -1181,7 +1181,7 @@
 	if (res.type == RTN_LOCAL) {
 		int result;
 		result = fib_validate_source(saddr, daddr, tos, loopback_dev.ifindex,
-					     dev, &spec_dst, &itag);
+					     dev, &spec_dst, &itag, 1);
 		if (result < 0)
 			goto martian_source;
 		if (result)
@@ -1206,7 +1206,7 @@
 		return -EINVAL;
 	}
 
-	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(res), dev, &spec_dst, &itag);
+	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(res), dev, &spec_dst, &itag, 0);
 	if (err < 0)
 		goto martian_source;
 
@@ -1279,7 +1279,7 @@
 	if (ZERONET(saddr)) {
 		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
 	} else {
-		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag);
+		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag, 1);
 		if (err < 0)
 			goto martian_source;
 		if (err)
--- v2.2.19/linux/Documentation/proc.txt~	Sat Oct 21 12:12:42 2000
+++ linux/Documentation/proc.txt	Sun Jul  1 14:27:55 2001
@@ -1182,6 +1182,16 @@
    against your internal networks (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
    Accept ICMP redirect messages only for gateways, listed in
    default gateway list. Enabled by default.
--- v2.2.19/linux/Documentation/networking/ip-sysctl.txt~	Sat Oct 21 12:11:52 2000
+++ linux/Documentation/networking/ip-sysctl.txt	Sun Jul  1 14:41:33 2001
@@ -149,6 +149,17 @@
 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.
