diff -ur v2.4.28/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt
--- v2.4.28/linux/Documentation/filesystems/proc.txt	2003-06-14 08:41:59.000000000 +0300
+++ linux/Documentation/filesystems/proc.txt	2004-11-18 09:01:35.493626944 +0200
@@ -1550,6 +1550,18 @@
 (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
 ----------------
 
@@ -1567,6 +1579,16 @@
 
 Determines whether to send ICMP redirects to other hosts.
 
+hidden
+------
+
+Hide addresses attached to this device from other devices.
+Such addresses will never be selected by source address autoselection
+mechanism, host does not answer broadcast ARP requests for them,
+does not announce them as source address of ARP requests, but they
+are still reachable via IP. This flag is activated only if it is
+enabled both in specific device section and in "all" section.
+
 Routing settings
 ----------------
 
diff -ur v2.4.28/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.4.28/linux/Documentation/networking/ip-sysctl.txt	2004-08-08 10:56:45.000000000 +0300
+++ linux/Documentation/networking/ip-sysctl.txt	2004-11-18 09:01:35.494626792 +0200
@@ -423,6 +423,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.
@@ -568,6 +579,14 @@
 	The max value from conf/{all,interface}/arp_ignore is used
 	when ARP request is received on the {interface}
 
+hidden - BOOLEAN
+	Hide addresses attached to this device from other devices.
+	Such addresses will never be selected by source address autoselection
+	mechanism, host does not answer broadcast ARP requests for them,
+	does not announce them as source address of ARP requests, but they
+	are still reachable via IP. This flag is activated only if it is
+	enabled both in specific device section and in "all" section.
+
 tag - INTEGER
 	Allows you to write a number, which can be used as required.
 	Default value is 0.
diff -ur v2.4.28/linux/include/linux/in_route.h linux/include/linux/in_route.h
--- v2.4.28/linux/include/linux/in_route.h	1998-06-12 08:52:33.000000000 +0300
+++ linux/include/linux/in_route.h	2004-11-18 09:01:35.495626640 +0200
@@ -13,6 +13,7 @@
 #define RTCF_DIRECTDST	0x00020000
 #define RTCF_REDIRECTED	0x00040000
 #define RTCF_TPROXY	0x00080000
+#define RTCF_NOARP	0x00100000
 
 #define RTCF_FAST	0x00200000
 #define RTCF_MASQ	0x00400000
diff -ur v2.4.28/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.4.28/linux/include/linux/inetdevice.h	2004-04-14 23:14:10.000000000 +0300
+++ linux/include/linux/inetdevice.h	2004-11-18 09:01:35.495626640 +0200
@@ -17,11 +17,13 @@
 	int	forwarding;
 	int	mc_forwarding;
 	int	tag;
+	int	hidden;
 	int     arp_filter;
 	int	arp_announce;
 	int	arp_ignore;
 	int	medium_id;
 	int	force_igmp_version;
+	int	forward_shared;
 	void	*sysctl;
 };
 
@@ -58,6 +60,7 @@
 
 #define IN_DEV_LOG_MARTIANS(in_dev)	(ipv4_devconf.log_martians || (in_dev)->cnf.log_martians)
 #define IN_DEV_PROXY_ARP(in_dev)	(ipv4_devconf.proxy_arp || (in_dev)->cnf.proxy_arp)
+#define IN_DEV_HIDDEN(in_dev)		((in_dev)->cnf.hidden && ipv4_devconf.hidden)
 #define IN_DEV_SHARED_MEDIA(in_dev)	(ipv4_devconf.shared_media || (in_dev)->cnf.shared_media)
 #define IN_DEV_TX_REDIRECTS(in_dev)	(ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects)
 #define IN_DEV_SEC_REDIRECTS(in_dev)	(ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects)
@@ -74,6 +77,8 @@
 #define IN_DEV_ARP_ANNOUNCE(in_dev)	(max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce))
 #define IN_DEV_ARP_IGNORE(in_dev)	(max(ipv4_devconf.arp_ignore, (in_dev)->cnf.arp_ignore))
 
+#define IN_DEV_FORWARD_SHARED(in_dev)	((in_dev)->cnf.forward_shared && ipv4_devconf.forward_shared)
+
 struct in_ifaddr
 {
 	struct in_ifaddr	*ifa_next;
diff -ur v2.4.28/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- v2.4.28/linux/include/linux/rtnetlink.h	2004-08-08 10:56:48.000000000 +0300
+++ linux/include/linux/rtnetlink.h	2004-11-18 09:01:35.496626488 +0200
@@ -171,6 +171,7 @@
 #define RTM_F_CLONED		0x200	/* This route is cloned		*/
 #define RTM_F_EQUALIZE		0x400	/* Multipath equalizer: NI	*/
 #define RTM_F_PREFIX		0x800	/* Prefix addresses		*/
+#define RTM_F_NOARP		0x1000	/* Disable ARP for this route	*/
 
 /* Reserved table identifiers */
 
@@ -323,6 +324,7 @@
 /* ifa_flags */
 
 #define IFA_F_SECONDARY		0x01
+#define IFA_F_HIDDEN		0x02
 
 #define IFA_F_DEPRECATED	0x20
 #define IFA_F_TENTATIVE		0x40
diff -ur v2.4.28/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.4.28/linux/include/linux/sysctl.h	2004-08-08 10:56:48.000000000 +0300
+++ linux/include/linux/sysctl.h	2004-11-18 09:01:35.497626336 +0200
@@ -375,6 +375,8 @@
 	NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
 	NET_IPV4_CONF_ARP_ANNOUNCE=18,
 	NET_IPV4_CONF_ARP_IGNORE=19,
+	NET_IPV4_CONF_HIDDEN=20,
+	NET_IPV4_CONF_FORWARD_SHARED=21,
 };
 
 /* /proc/sys/net/ipv4/netfilter */
diff -ur v2.4.28/linux/include/net/ip_fib.h linux/include/net/ip_fib.h
--- v2.4.28/linux/include/net/ip_fib.h	2001-11-13 03:24:05.000000000 +0200
+++ linux/include/net/ip_fib.h	2004-11-18 09:01:35.497626336 +0200
@@ -203,7 +203,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 net_device *dev, u32 *spec_dst, u32 *itag);
+			       struct net_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 */
diff -ur v2.4.28/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.4.28/linux/net/ipv4/arp.c	2004-11-18 08:30:33.000000000 +0200
+++ linux/net/ipv4/arp.c	2004-11-18 09:01:53.485891704 +0200
@@ -71,6 +71,9 @@
  *					bonding can change the skb before
  *					sending (e.g. insert 8021q tag).
  *		Harald Welte	:	convert to make use of jenkins hash
+ *		Julian Anastasov:	"hidden" flag: hide the
+ *					interface and don't reply for it
+ *		Julian Anastasov:	Per-route ARP control
  */
 
 #include <linux/types.h>
@@ -323,21 +326,42 @@
 	u32 target = *(u32*)neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
 	struct in_device *in_dev = in_dev_get(dev);
+	struct rtable *rt;
+	struct in_device *in_dev2 = NULL;
+	struct net_device *dev2 = NULL;
 
 	if (!in_dev)
 		return;
 
+	/* Determine source IP for the probing packet. */
+	if (skb != NULL) {
+		rt = (struct rtable*)skb->dst;
+		if (rt && !rt->rt_iif && !(rt->rt_flags & RTCF_NOARP) &&
+		    (dev2 = ip_dev_find(skb->nh.iph->saddr)) != NULL &&
+		    (in_dev2 = in_dev_get(dev2)) != NULL &&
+		    !IN_DEV_HIDDEN(in_dev2))
+			saddr = rt->rt_src;
+	}
+	if (!saddr) {
+		if (!ip_route_output(&rt, target, 0, 0, dev->ifindex)) {
+			saddr = rt->rt_src;
+			ip_rt_put(rt);
+		}
+	}
+
 	switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
 	default:
 	case 0:		/* By default announce any local IP */
+		if (saddr)
+			break;
 		if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
 			saddr = skb->nh.iph->saddr;
 		break;
 	case 1:		/* Restrict announcements of saddr in same subnet */
 		if (!skb)
 			break;
-		saddr = skb->nh.iph->saddr;
-		if (inet_addr_type(saddr) == RTN_LOCAL) {
+		if (saddr || (saddr = skb->nh.iph->saddr,
+			      inet_addr_type(saddr) == RTN_LOCAL)) {
 			/* saddr should be known to target */
 			if (inet_addr_onlink(in_dev, target, saddr))
 				break;
@@ -348,6 +372,11 @@
 		break;
 	}
 
+	if (dev2) {
+		if (in_dev2)
+			in_dev_put(in_dev2);
+		dev_put(dev2);
+	}
 	if (in_dev)
 		in_dev_put(in_dev);
 	if (!saddr)
@@ -407,22 +436,57 @@
 	return !inet_confirm_addr(dev, sip, tip, scope);
 }
 
-static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
+static int arp_filter(struct sk_buff *skb, __u32 sip, __u32 tip,
+		struct in_device *in_dev)
 {
 	struct rtable *rt;
 	int flag = 0; 
-	/*unsigned long now; */
 
+	if (!IN_DEV_ARPFILTER(in_dev))
+		return 0;
+
+	/* Always answer direct queries. */
+	if (skb->pkt_type == PACKET_HOST)
+		return 0;
+
+	/* Then check routes:
+	 * primarily, this check is used to not to answer to some requests if
+	 * several interfaces are connected to the same segment.
+	 * This check also may be used for manual control of who sees IP
+	 * addresses at which link-level addresses by installing prohibiting
+	 * routes.  -- 2001/05/20  SAW
+	 */
 	if (ip_route_output(&rt, sip, tip, 0, 0) < 0) 
 		return 1;
-	if (rt->u.dst.dev != dev) { 
+	if (rt->u.dst.dev != in_dev->dev) { 
 		NET_INC_STATS_BH(ArpFilter);
 		flag = 1;
 	} 
 	ip_rt_put(rt); 
-	return flag; 
+
+	return flag;
 } 
 
+static int arp_hidden(u32 tip, struct net_device *dev)
+{
+	struct net_device *dev2 = NULL;
+	struct in_device *in_dev2 = NULL;
+	int ret = 0;
+
+	if (!ipv4_devconf.hidden)
+		return 0;
+
+	if ((dev2 = ip_dev_find(tip)) && dev2 != dev &&
+	    (in_dev2 = in_dev_get(dev2)) && IN_DEV_HIDDEN(in_dev2))
+		ret = 1;
+	if (dev2) {
+		if (in_dev2)
+			in_dev_put(in_dev2);
+		dev_put(dev2);
+	}
+	return ret;
+}
+
 /* OBSOLETE FUNCTIONS */
 
 /*
@@ -844,6 +908,7 @@
 	if (sip == 0) {
 		if (arp->ar_op == htons(ARPOP_REQUEST) &&
 		    inet_addr_type(tip) == RTN_LOCAL &&
+		    !arp_hidden(tip, dev) &&
 		    !arp_ignore(in_dev,dev,sip,tip))
 			arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);
 		goto out;
@@ -861,9 +926,13 @@
 				int dont_send = 0;
 
 				if (!dont_send)
+					dont_send |= (rt->rt_flags & RTCF_NOARP);
+				if (!dont_send)
 					dont_send |= arp_ignore(in_dev,dev,sip,tip);
 				if (!dont_send && IN_DEV_ARPFILTER(in_dev))
-					dont_send |= arp_filter(sip,tip,dev); 
+					dont_send |= arp_filter(skb,sip,tip,in_dev); 
+				if (!dont_send && skb->pkt_type != PACKET_HOST)
+					dont_send |= arp_hidden(tip,dev); 
 				if (!dont_send)
 					arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
 
@@ -878,6 +947,9 @@
 				if (n)
 					neigh_release(n);
 
+				if (rt->rt_flags & RTCF_NOARP)
+					goto out;
+
 				if (skb->stamp.tv_sec == 0 ||
 				    skb->pkt_type == PACKET_HOST ||
 				    in_dev->arp_parms->proxy_delay == 0) {
diff -ur v2.4.28/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.4.28/linux/net/ipv4/devinet.c	2004-08-08 10:56:48.000000000 +0300
+++ linux/net/ipv4/devinet.c	2004-11-18 09:01:35.501625728 +0200
@@ -773,7 +773,8 @@
 
 		read_lock(&in_dev->lock);
 		for_primary_ifa(in_dev) {
-			if (ifa->ifa_scope != RT_SCOPE_LINK &&
+			if (!IN_DEV_HIDDEN(in_dev) &&
+			    ifa->ifa_scope != RT_SCOPE_LINK &&
 			    ifa->ifa_scope <= scope) {
 				read_unlock(&in_dev->lock);
 				read_unlock(&inetdev_lock);
@@ -1151,7 +1152,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[20];
+	ctl_table devinet_vars[22];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -1197,6 +1198,9 @@
 	{NET_IPV4_CONF_TAG, "tag",
 	 &ipv4_devconf.tag, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
+	{NET_IPV4_CONF_HIDDEN, "hidden",
+	 &ipv4_devconf.hidden, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
 	{NET_IPV4_CONF_ARPFILTER, "arp_filter",
 	 &ipv4_devconf.arp_filter, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
@@ -1209,6 +1213,9 @@
 	{NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version",
 	 &ipv4_devconf.force_igmp_version, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
+	{NET_IPV4_CONF_FORWARD_SHARED, "forward_shared",
+	 &ipv4_devconf.forward_shared, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
 	 {0}},
 
 	{{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}},
diff -ur v2.4.28/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.4.28/linux/net/ipv4/fib_frontend.c	2003-08-25 22:06:13.000000000 +0300
+++ linux/net/ipv4/fib_frontend.c	2004-11-18 09:01:35.501625728 +0200
@@ -204,13 +204,15 @@
  */
 
 int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
-			struct net_device *dev, u32 *spec_dst, u32 *itag)
+			struct net_device *dev, u32 *spec_dst, u32 *itag,
+			int our)
 {
 	struct in_device *in_dev;
 	struct rt_key key;
 	struct fib_result res;
 	int no_addr, rpf;
 	int ret;
+	int fwdsh = 0;
 
 	key.dst = src;
 	key.src = dst;
@@ -225,6 +227,7 @@
 	if (in_dev) {
 		no_addr = in_dev->ifa_list == NULL;
 		rpf = IN_DEV_RPFILTER(in_dev);
+		fwdsh = IN_DEV_FORWARD_SHARED(in_dev);
 	}
 	read_unlock(&inetdev_lock);
 
@@ -233,7 +236,12 @@
 
 	if (fib_lookup(&key, &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);
@@ -253,6 +261,8 @@
 	if (rpf)
 		goto e_inval;
 	key.oif = dev->ifindex;
+	if (fwdsh)
+		key.iif = loopback_dev.ifindex;
 
 	ret = 0;
 	if (fib_lookup(&key, &res) == 0) {
@@ -445,6 +455,9 @@
 	req.rtm.rtm_protocol = RTPROT_KERNEL;
 	req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
 	req.rtm.rtm_type = type;
+	if (ifa->ifa_flags & IFA_F_HIDDEN && type == RTN_LOCAL &&
+	    cmd == RTM_NEWROUTE)
+		req.rtm.rtm_flags |= RTM_F_NOARP;
 
 	rta.rta_dst = &dst;
 	rta.rta_prefsrc = &ifa->ifa_local;
diff -ur v2.4.28/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.4.28/linux/net/ipv4/route.c	2004-11-18 08:30:33.000000000 +0200
+++ linux/net/ipv4/route.c	2004-11-18 09:01:35.503625424 +0200
@@ -1325,7 +1325,7 @@
 			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);
@@ -1485,11 +1485,14 @@
 	if (res.type == RTN_BROADCAST)
 		goto brd_input;
 
+	if (res.fi && res.fi->fib_flags & RTM_F_NOARP)
+		flags |= RTCF_NOARP;
+
 	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)
@@ -1516,7 +1519,7 @@
 	}
 
 	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(res), dev,
-				  &spec_dst, &itag);
+				  &spec_dst, &itag, 0);
 	if (err < 0)
 		goto martian_source;
 
@@ -1600,7 +1603,7 @@
 		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)
@@ -1922,6 +1925,9 @@
 	if (res.type == RTN_NAT)
 		goto e_inval;
 
+	if (res.fi && res.fi->fib_flags & RTM_F_NOARP)
+		flags |= RTCF_NOARP;
+
 	if (res.type == RTN_LOCAL) {
 		if (!key.src)
 			key.src = key.dst;
@@ -2125,6 +2131,8 @@
 	r->rtm_flags	= (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED;
 	if (rt->rt_flags & RTCF_NOTIFY)
 		r->rtm_flags |= RTM_F_NOTIFY;
+	if (rt->rt_flags & RTCF_NOARP)
+		r->rtm_flags |= RTM_F_NOARP;
 	RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
 	if (rt->key.src) {
 		r->rtm_src_len = 32;
@@ -2249,6 +2257,8 @@
 	skb->dst = &rt->u.dst;
 	if (rtm->rtm_flags & RTM_F_NOTIFY)
 		rt->rt_flags |= RTCF_NOTIFY;
+	if (rtm->rtm_flags & RTM_F_NOARP)
+		rt->rt_flags |= RTCF_NOARP;
 
 	NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
 
