netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Restrict local IP announcements in ARP requests
@ 2004-02-08  9:59 Julian Anastasov
  2004-02-09 22:08 ` David S. Miller
  0 siblings, 1 reply; 17+ messages in thread
From: Julian Anastasov @ 2004-02-08  9:59 UTC (permalink / raw)
  To: netdev; +Cc: linux-net


	Hello,

	I'm opening again the discussion about src IP selection
in ARP requests. We know that there are tools and framework for
ARP filtering and mangling. The question is whether we need a
simple interface flag to restrict the local src IP address for cases
where the target hosts require sender to be from same known logical
subnet due to [wrong] policy or topology reasons.

	I'm proposing simple flag that controls the src selection
in our ARP requests. I named it arp_announce - mode used to define
different restriction levels for announcing the local source address
from IP packets in ARP requests:

0 - the current behavior: use any local address if possible

	as it appears it is not the most safe mode in some cases

1 - restrict saddr to the target's subnet

	this behavior is useful in setups where the target hosts
	have [sometimes default] policy to drop incoming requests by
	checking the src IP. The result is that we can announce
	only addresses from same logical subnet as the target.

2 - always use the best source address for this target

	This is the most restrictive mode that expects answer
	from the target host. In this case we can announce only
	preferred/primary IP address. Useful for setups where we
	do not want to announce secondary IPs, for example, if
	they are shared from many hosts.

Draft version can be found here:

http://www.ssi.bg/~ja/#arp_announce

and it is also appended here. Comments?

Regards

--
Julian Anastasov <ja@ssi.bg>

diff -ur v2.6.2/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.6.2/linux/Documentation/networking/ip-sysctl.txt	2004-02-05 00:23:10.000000000 +0200
+++ linux/Documentation/networking/ip-sysctl.txt	2004-02-08 11:35:04.617310560 +0200
@@ -486,6 +486,21 @@
 	conf/{all,interface}/arp_filter is set to TRUE,
 	it will be disabled otherwise
 
+arp_announce - INTEGER
+	Define different restriction levels for announcing the local
+	source IP address from IP packets in ARP requests sent on
+	interface:
+	0 - (default) Use any local address, configured on any interface
+	1 - Try to avoid local addresses that are not in the target's
+	subnet for this interface
+	2 - Always use the best source address for this target
+
+	The max value from conf/{all,interface}/arp_announce is used.
+
+	Increasing the restriction level gives more chance for
+	receiving answer from the resolved target while decreasing
+	the level announces more valid sender's information.
+
 tag - INTEGER
 	Allows you to write a number, which can be used as required.
 	Default value is 0.
diff -ur v2.6.2/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.6.2/linux/include/linux/inetdevice.h	2003-08-23 19:42:33.000000000 +0300
+++ linux/include/linux/inetdevice.h	2004-02-07 17:57:38.000000000 +0200
@@ -18,6 +18,7 @@
 	int	mc_forwarding;
 	int	tag;
 	int     arp_filter;
+	int	arp_announce;
 	int	medium_id;
 	int	no_xfrm;
 	int	no_policy;
@@ -70,6 +71,7 @@
 	  (ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects)))
 
 #define IN_DEV_ARPFILTER(in_dev)	(ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
+#define IN_DEV_ARP_ANNOUNCE(in_dev)	(max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce))
 
 struct in_ifaddr
 {
diff -ur v2.6.2/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.6.2/linux/include/linux/sysctl.h	2004-02-05 00:23:17.000000000 +0200
+++ linux/include/linux/sysctl.h	2004-02-07 18:01:58.000000000 +0200
@@ -360,6 +360,7 @@
 	NET_IPV4_CONF_MEDIUM_ID=14,
 	NET_IPV4_CONF_NOXFRM=15,
 	NET_IPV4_CONF_NOPOLICY=16,
+	NET_IPV4_CONF_ARP_ANNOUNCE=17,
 };
 
 /* /proc/sys/net/ipv4/netfilter */
diff -ur v2.6.2/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.6.2/linux/net/ipv4/arp.c	2004-02-05 00:23:18.000000000 +0200
+++ linux/net/ipv4/arp.c	2004-02-08 11:37:24.551037400 +0200
@@ -321,15 +321,57 @@
 
 static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
 {
-	u32 saddr;
+	u32 saddr = 0;
 	u8  *dst_ha = NULL;
 	struct net_device *dev = neigh->dev;
 	u32 target = *(u32*)neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
+	struct rtable *rt;
+	struct in_device *in_dev = in_dev_get(dev);
 
-	if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
+	if (!in_dev)
+		return;
+
+	switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
+	default:
+	case 0:		/* By default announce any local IP */
+		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 || !(rt = (struct rtable *) skb->dst) || rt->fl.iif)
+			break;
 		saddr = skb->nh.iph->saddr;
-	else
+		/* rt_src is always a local address */
+		if (saddr == rt->rt_src || inet_addr_type(saddr) == RTN_LOCAL) {
+			/* saddr should be known to target */
+			if (inet_addr_onlink(in_dev, target, saddr))
+				break;
+		}
+		saddr = 0;
+		break;
+	case 2:		/* Avoid secondary IPs, get a primary/preferred one */
+#if 0
+		{
+			struct flowi fl = {
+				.nl_u = { .ip4_u = { .daddr = target } },
+				.oif = dev->ifindex };
+
+			in_dev_put(in_dev);
+			in_dev = NULL;
+			if (ip_route_output_key(&rt, &fl) < 0)
+				return;
+			saddr = rt->rt_src;
+			ip_rt_put(rt);
+		}
+#endif
+
+		break;
+	}
+
+	if (in_dev)
+		in_dev_put(in_dev);
+	if (!saddr)
 		saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
 
 	if ((probes -= neigh->parms->ucast_probes) < 0) {
diff -ur v2.6.2/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.6.2/linux/net/ipv4/devinet.c	2004-02-05 00:23:18.000000000 +0200
+++ linux/net/ipv4/devinet.c	2004-02-07 18:03:04.000000000 +0200
@@ -1132,7 +1132,7 @@
 
 static struct devinet_sysctl_table {
 	struct ctl_table_header *sysctl_header;
-	ctl_table		devinet_vars[17];
+	ctl_table		devinet_vars[18];
 	ctl_table		devinet_dev[2];
 	ctl_table		devinet_conf_dir[2];
 	ctl_table		devinet_proto_dir[2];
@@ -1252,6 +1252,14 @@
 			.proc_handler	= &proc_dointvec,
 		},
 		{
+			.ctl_name	= NET_IPV4_CONF_ARP_ANNOUNCE,
+			.procname	= "arp_announce",
+			.data		= &ipv4_devconf.arp_announce,
+			.maxlen		= sizeof(int),
+			.mode		= 0644,
+			.proc_handler	= &proc_dointvec,
+		},
+		{
 			.ctl_name	= NET_IPV4_CONF_NOXFRM,
 			.procname	= "disable_xfrm",
 			.data		= &ipv4_devconf.no_xfrm,

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-08  9:59 Restrict local IP announcements in ARP requests Julian Anastasov
@ 2004-02-09 22:08 ` David S. Miller
  2004-02-09 22:20   ` David S. Miller
  2004-02-09 23:06   ` Julian Anastasov
  0 siblings, 2 replies; 17+ messages in thread
From: David S. Miller @ 2004-02-09 22:08 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: netdev, linux-net

On Sun, 8 Feb 2004 11:59:35 +0200 (EET)
Julian Anastasov <ja@ssi.bg> wrote:

> 	I'm proposing simple flag that controls the src selection
> in our ARP requests. I named it arp_announce - mode used to define
> different restriction levels for announcing the local source address
> from IP packets in ARP requests:

I'm fine with this patch, although it appears incomplete because:

> 2 - always use the best source address for this target

The code handling this case is "#if 0/#endif" commented out in your
patch.

Finish this thing up, and as a birthday present to everyone I'll also
add an IN_DEV_ARP_IGNORE flag for inet devices to so people can control
complete ARP ignoring via a global/per-device sysctl.

Hopefully, combined, this will get all the virtual server maniacs off
of my back :-)

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-09 22:08 ` David S. Miller
@ 2004-02-09 22:20   ` David S. Miller
  2004-02-09 23:06   ` Julian Anastasov
  1 sibling, 0 replies; 17+ messages in thread
From: David S. Miller @ 2004-02-09 22:20 UTC (permalink / raw)
  To: David S. Miller; +Cc: ja, netdev, linux-net

On Mon, 9 Feb 2004 14:08:53 -0800
"David S. Miller" <davem@redhat.com> wrote:

> as a birthday present to everyone I'll also add an IN_DEV_ARP_IGNORE
> flag for inet devices to so people can control
> complete ARP ignoring via a global/per-device sysctl.

Ok, does this do what everyone wants?  Speak now or forever hold your peace
on this issue :-)

I'll add this to 2.6.x and 2.4.x if folks are OK with it.  Write this date
down on your calendars, I doubt I'll capitulate like this ever again 8-)

===== Documentation/networking/ip-sysctl.txt 1.20 vs edited =====
--- 1.20/Documentation/networking/ip-sysctl.txt	Mon Feb  2 10:20:58 2004
+++ edited/Documentation/networking/ip-sysctl.txt	Mon Feb  9 14:08:57 2004
@@ -499,6 +499,15 @@
 	conf/{all,interface}/arp_filter is set to TRUE,
 	it will be disabled otherwise
 
+arp_ignore - BOOLEAN
+	0 - (default) Process ARP requests.
+	1 - Ignore ARP requests.
+
+	ARP requests received on a given interface will be ignored if
+	at least one of conf/{all,interface}/arp_ignore is set to TRUE.
+	ARP requests will be processed otherwise (barring any other
+	restrictive controls such as 'arp_filter' documented above).
+
 tag - INTEGER
 	Allows you to write a number, which can be used as required.
 	Default value is 0.
===== include/linux/inetdevice.h 1.7 vs edited =====
--- 1.7/include/linux/inetdevice.h	Thu Jan 29 14:57:46 2004
+++ edited/include/linux/inetdevice.h	Mon Feb  9 14:09:31 2004
@@ -18,6 +18,7 @@
 	int	mc_forwarding;
 	int	tag;
 	int     arp_filter;
+	int     arp_ignore;
 	int	medium_id;
 	int	no_xfrm;
 	int	no_policy;
@@ -71,6 +72,7 @@
 	  (ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects)))
 
 #define IN_DEV_ARPFILTER(in_dev)	(ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
+#define IN_DEV_ARPIGNORE(in_dev)	(ipv4_devconf.arp_ignore || (in_dev)->cnf.arp_ignore)
 
 struct in_ifaddr
 {
===== include/linux/sysctl.h 1.60 vs edited =====
--- 1.60/include/linux/sysctl.h	Fri Feb  6 19:37:57 2004
+++ edited/include/linux/sysctl.h	Mon Feb  9 14:09:51 2004
@@ -362,6 +362,7 @@
 	NET_IPV4_CONF_NOXFRM=15,
 	NET_IPV4_CONF_NOPOLICY=16,
 	NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
+	NET_IPV4_CONF_ARP_IGNORE=18,
 };
 
 /* /proc/sys/net/ipv4/netfilter */
===== net/ipv4/arp.c 1.36 vs edited =====
--- 1.36/net/ipv4/arp.c	Fri Feb  6 16:00:17 2004
+++ edited/net/ipv4/arp.c	Mon Feb  9 14:10:27 2004
@@ -779,7 +779,9 @@
 			n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 			if (n) {
 				int dont_send = 0;
-				if (IN_DEV_ARPFILTER(in_dev))
+				if (IN_DEV_ARPIGNORE(in_dev))
+					dont_send = 1;
+				else if (IN_DEV_ARPFILTER(in_dev))
 					dont_send |= arp_filter(sip,tip,dev); 
 				if (!dont_send)
 					arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
===== net/ipv4/devinet.c 1.24 vs edited =====
--- 1.24/net/ipv4/devinet.c	Thu Jan 29 14:57:46 2004
+++ edited/net/ipv4/devinet.c	Mon Feb  9 14:12:38 2004
@@ -1132,7 +1132,7 @@
 
 static struct devinet_sysctl_table {
 	struct ctl_table_header *sysctl_header;
-	ctl_table		devinet_vars[18];
+	ctl_table		devinet_vars[19];
 	ctl_table		devinet_dev[2];
 	ctl_table		devinet_conf_dir[2];
 	ctl_table		devinet_proto_dir[2];
@@ -1277,6 +1277,14 @@
 			.mode		= 0644,
 			.proc_handler	= &ipv4_doint_and_flush,
 			.strategy	= &ipv4_doint_and_flush_strategy,
+		},
+		{
+			.ctl_name	= NET_IPV4_CONF_ARP_IGNORE,
+			.procname	= "arp_ignore",
+			.data		= &ipv4_devconf.arp_ignore,
+			.maxlen		= sizeof(int),
+			.mode		= 0644,
+			.proc_handler	= &proc_dointvec,
 		},
 	},
 	.devinet_dev = {

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-09 22:08 ` David S. Miller
  2004-02-09 22:20   ` David S. Miller
@ 2004-02-09 23:06   ` Julian Anastasov
  2004-02-09 23:10     ` David S. Miller
  1 sibling, 1 reply; 17+ messages in thread
From: Julian Anastasov @ 2004-02-09 23:06 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, linux-net


	Hello,

On Mon, 9 Feb 2004, David S. Miller wrote:

> I'm fine with this patch, although it appears incomplete because:

	Of course :) I'm still thinking on it, for example:

- do we need to complicate the things in arp_solicit and to
announce not only local IPs but also sender IPs for which we
support proxy_arp. But may be it is better not to complicate
the arp_solicit routine because it can detect different skbs
to same target, each with different saddr, so this is only a
matter of optimization.

	I'll send you final diff in the next days after resolving
this ifdef, I'm giving myself and the other gurus some days for
thinking :)

> > 2 - always use the best source address for this target
>
> The code handling this case is "#if 0/#endif" commented out in your
> patch.

	I just wanted to know if output route is better to use
in this case? Or it is better to use inet_select_addr?

> Finish this thing up, and as a birthday present to everyone I'll also
> add an IN_DEV_ARP_IGNORE flag for inet devices to so people can control
> complete ARP ignoring via a global/per-device sysctl.
>
> Hopefully, combined, this will get all the virtual server maniacs off
> of my back :-)

	Ah, no, forget about ARP_IGNORE :) Nobody wants this :)
As for IPVS like setups, the requirements need per IP tunning which
is possible only with some kind of filtering, not a global flag,
especially for the input device. Note that the "hidden" flag
is checked for the target device, this was the only way to
differentiate by device. May be this is a proof arp_announce is
not for IPVS :) It is mostly to work with other stacks because
I'm flooded with emails about how Linux ARP can be more friendly.

Regards

--
Julian Anastasov <ja@ssi.bg>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-09 23:06   ` Julian Anastasov
@ 2004-02-09 23:10     ` David S. Miller
  2004-02-10  0:31       ` Julian Anastasov
  2004-02-10  1:00       ` Julian Anastasov
  0 siblings, 2 replies; 17+ messages in thread
From: David S. Miller @ 2004-02-09 23:10 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: netdev, linux-net

On Tue, 10 Feb 2004 01:06:15 +0200 (EET)
Julian Anastasov <ja@ssi.bg> wrote:

> As for IPVS like setups, the requirements need per IP tunning which
> is possible only with some kind of filtering, not a global flag,
> especially for the input device. Note that the "hidden" flag
> is checked for the target device, this was the only way to
> differentiate by device. May be this is a proof arp_announce is
> not for IPVS :) It is mostly to work with other stacks because
> I'm flooded with emails about how Linux ARP can be more friendly.

So this new 'arp_announce' change suggestion will preempt any need for
hidden and make everyone happy?

About output_route vs. inet_select_addr(), probably the latter is better.
Your goal is to differentiate between primary and seconday addrs on a device
right?  Route lookup is also more expensive, probably.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-09 23:10     ` David S. Miller
@ 2004-02-10  0:31       ` Julian Anastasov
  2004-02-12  4:22         ` David S. Miller
  2004-02-10  1:00       ` Julian Anastasov
  1 sibling, 1 reply; 17+ messages in thread
From: Julian Anastasov @ 2004-02-10  0:31 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, linux-net


	Hello,

On Mon, 9 Feb 2004, David S. Miller wrote:

> > not for IPVS :) It is mostly to work with other stacks because
> > I'm flooded with emails about how Linux ARP can be more friendly.
>
> So this new 'arp_announce' change suggestion will preempt any need for
> hidden and make everyone happy?

	For IPVS like setups it solves only one part:
arp_announce=2 but for such setups we still need per IP filtering
of ARP requests which is not possible to filter with ip rules.
If you look at http://www.ssi.bg/~ja/hidden-2.5.67-1.diff
you will see that:

- the arp_solicit change is solvable with arp_announce=2. If
hidden touches there it needs IP lookup. The good news is that
inet_addr_type is replaced with ip_dev_find.

	If hidden does not change arp_solicit then the users will use:

	{all,lo}/hidden=1, eth0/arp_announce=2

	If hidden changes arp_solicit then only hidden will be used

- hidden adds ip_dev_find call in arp_rcv for the broadcast case,
and only if hidden is enabled with all/hidden=1, so it is ugly
but fast if all/hidden=0

- hidden changes inet_select_addr() which is not needed for
IPVS setups and can be solved with careful preferred source usage,
so this change can be ignored

	So, if hidden exists and is disabled it will not delay
too much the processing but it is true that both arp_rcv and
arp_solicit become more and more loaded with ugly checks.
You do not need to decide today about it :)

	Another question while I'm looking at arp_rcv:

- what happens if request comes with SIP=0, should we provide
answer (proxy_arp) if there is valid remote target? Can be useful
for setups where we split a logical subnet. But solving
this problem will require cleaning up the arp_process function.
In any case, it does not look so hard to me :)

> About output_route vs. inet_select_addr(), probably the latter is better.
> Your goal is to differentiate between primary and seconday addrs on a device
> right?  Route lookup is also more expensive, probably.

	ok

Regards

--
Julian Anastasov <ja@ssi.bg>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-09 23:10     ` David S. Miller
  2004-02-10  0:31       ` Julian Anastasov
@ 2004-02-10  1:00       ` Julian Anastasov
  2004-02-12  4:16         ` David S. Miller
  1 sibling, 1 reply; 17+ messages in thread
From: Julian Anastasov @ 2004-02-10  1:00 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, linux-net


	Hello,

	May be this will be something like final patch, I removed
the games with skb->dst because there are cases where SNAT can take
place after input routing, etc:

http://www.ssi.bg/~ja/arp_announce-2.6.2-3.diff

	If you like it in this way you can apply now or after
some days or to delay it if we want to combine it with other
device flags or changes.

Regards

--
Julian Anastasov <ja@ssi.bg>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-10  1:00       ` Julian Anastasov
@ 2004-02-12  4:16         ` David S. Miller
  2004-02-12 23:50           ` Julian Anastasov
  0 siblings, 1 reply; 17+ messages in thread
From: David S. Miller @ 2004-02-12  4:16 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: netdev, linux-net

On Tue, 10 Feb 2004 03:00:24 +0200 (EET)
Julian Anastasov <ja@ssi.bg> wrote:

> 	If you like it in this way you can apply now or after
> some days or to delay it if we want to combine it with other
> device flags or changes.

I like the patch, but I want the documentation changed.

If you'll recall, one of the big problems Alexey and myself
had with the new ARP saddr selection behavior you propose is
that it assumes that: if we do not know of a certain subnet
being on a link than this subnet does not exist there.

In some environments this assumption holds.  But "some != all"
as I often say to a friend of mine :-)

No router has this knowledge completely, and in many environments
such an assumption does not hold.

I know you understand this, which is why your patch keeps the
current behavior the default.

But I want the docs for the sysctl to talk about this.  Something
simple like:

+	1 - Try to avoid local addresses that are not in the target's
+	subnet for this interface as far as we know.  In some environments
+	subnets may be active that this system is not aware of, thus this
+	setting might cause problems in such cases.

Tweak it however you wish, just get the idea/warning across.

I'd also prefer if you at least lightly define what "best" source address
means in the context of arp_announce==2.

Thanks.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-10  0:31       ` Julian Anastasov
@ 2004-02-12  4:22         ` David S. Miller
  2004-02-15 10:04           ` Julian Anastasov
  0 siblings, 1 reply; 17+ messages in thread
From: David S. Miller @ 2004-02-12  4:22 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: netdev, linux-net

On Tue, 10 Feb 2004 02:31:23 +0200 (EET)
Julian Anastasov <ja@ssi.bg> wrote:

> 	So, if hidden exists and is disabled it will not delay
> too much the processing but it is true that both arp_rcv and
> arp_solicit become more and more loaded with ugly checks.

The hidden patch does a hundred different things, that's what makes
it so undigestable. :)

Let us assume your arp_announce patch is applied.  Given that, plus the
things you've mentioned, only a tiny piece of functionality is
really needed from that hidden patch.

Why don't you extract out just the needed part, and toss together
an email with that patch explaining that specific behavior change?

Thanks.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-12  4:16         ` David S. Miller
@ 2004-02-12 23:50           ` Julian Anastasov
  2004-02-14  7:24             ` David S. Miller
  0 siblings, 1 reply; 17+ messages in thread
From: Julian Anastasov @ 2004-02-12 23:50 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, linux-net


	Hello,

On Wed, 11 Feb 2004, David S. Miller wrote:

> But I want the docs for the sysctl to talk about this.  Something
> simple like:
>
> +	1 - Try to avoid local addresses that are not in the target's
> +	subnet for this interface as far as we know.  In some environments
> +	subnets may be active that this system is not aware of, thus this
> +	setting might cause problems in such cases.
>
> Tweak it however you wish, just get the idea/warning across.
>
> I'd also prefer if you at least lightly define what "best" source address
> means in the context of arp_announce==2.

	I hope I explained them using my non-native english :)
May be the info is not good enough and can be improved. This is
against latest bk (there will be no conflict with the recently added 
flag):

http://www.ssi.bg/~ja/arp_announce-2.6.2-4.diff

Regards

--
Julian Anastasov <ja@ssi.bg>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-12 23:50           ` Julian Anastasov
@ 2004-02-14  7:24             ` David S. Miller
  2004-02-14 12:03               ` Julian Anastasov
  0 siblings, 1 reply; 17+ messages in thread
From: David S. Miller @ 2004-02-14  7:24 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: netdev, linux-net

On Fri, 13 Feb 2004 01:50:32 +0200 (EET)
Julian Anastasov <ja@ssi.bg> wrote:

> http://www.ssi.bg/~ja/arp_announce-2.6.2-4.diff

Ok, I eat this, please make a 2.4.x version against Marcelo's current tree.

The 2.6.x variant will go into 2.6.4-pre1 and the 2.4.x will go into 2.4.26-pre1

Thanks.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-14  7:24             ` David S. Miller
@ 2004-02-14 12:03               ` Julian Anastasov
  2004-02-14 20:37                 ` David S. Miller
  0 siblings, 1 reply; 17+ messages in thread
From: Julian Anastasov @ 2004-02-14 12:03 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, linux-net

[-- Attachment #1: Type: TEXT/PLAIN, Size: 368 bytes --]


	Hello,

On Fri, 13 Feb 2004, David S. Miller wrote:

> > http://www.ssi.bg/~ja/arp_announce-2.6.2-4.diff
>
> Ok, I eat this, please make a 2.4.x version against Marcelo's current tree.

	Attached, against rc2 which looks enough.

> The 2.6.x variant will go into 2.6.4-pre1 and the 2.4.x will go into 2.4.26-pre1

	very good

Regards

--
Julian Anastasov <ja@ssi.bg>

[-- Attachment #2: arp_announce for 2.4.25-rc2 --]
[-- Type: TEXT/PLAIN, Size: 5609 bytes --]

diff -ur v2.4.25-rc2/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.4.25-rc2/linux/Documentation/networking/ip-sysctl.txt	2003-06-14 08:41:59.000000000 +0300
+++ linux/Documentation/networking/ip-sysctl.txt	2004-02-14 11:00:31.528798088 +0200
@@ -481,6 +481,37 @@
 	conf/{all,interface}/arp_filter is set to TRUE,
 	it will be disabled otherwise
 
+arp_announce - INTEGER
+	Define different restriction levels for announcing the local
+	source IP address from IP packets in ARP requests sent on
+	interface:
+	0 - (default) Use any local address, configured on any interface
+	1 - Try to avoid local addresses that are not in the target's
+	subnet for this interface. This mode is useful when target
+	hosts reachable via this interface require the source IP
+	address in ARP requests to be part of their logical network
+	configured on the receiving interface. When we generate the
+	request we will check all our subnets that include the
+	target IP and will preserve the source address if it is from
+	such subnet. If there is no such subnet we select source
+	address according to the rules for level 2.
+	2 - Always use the best local address for this target.
+	In this mode we ignore the source address in the IP packet
+	and try to select local address that we prefer for talks with
+	the target host. Such local address is selected by looking
+	for primary IP addresses on all our subnets on the outgoing
+	interface that include the target IP address. If no suitable
+	local address is found we select the first local address
+	we have on the outgoing interface or on all other interfaces,
+	with the hope we will receive reply for our request and
+	even sometimes no matter the source IP address we announce.
+
+	The max value from conf/{all,interface}/arp_announce is used.
+
+	Increasing the restriction level gives more chance for
+	receiving answer from the resolved target while decreasing
+	the level announces more valid sender's information.
+
 tag - INTEGER
 	Allows you to write a number, which can be used as required.
 	Default value is 0.
diff -ur v2.4.25-rc2/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.4.25-rc2/linux/include/linux/inetdevice.h	2004-02-14 10:37:06.000000000 +0200
+++ linux/include/linux/inetdevice.h	2004-02-14 11:00:31.549794896 +0200
@@ -18,6 +18,7 @@
 	int	mc_forwarding;
 	int	tag;
 	int     arp_filter;
+	int	arp_announce;
 	int	medium_id;
 	int	force_igmp_version;
 	void	*sysctl;
@@ -69,6 +70,7 @@
 	  (ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects)))
 
 #define IN_DEV_ARPFILTER(in_dev)	(ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
+#define IN_DEV_ARP_ANNOUNCE(in_dev)	(max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce))
 
 struct in_ifaddr
 {
diff -ur v2.4.25-rc2/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.4.25-rc2/linux/include/linux/sysctl.h	2004-02-14 10:37:06.000000000 +0200
+++ linux/include/linux/sysctl.h	2004-02-14 11:00:31.550794744 +0200
@@ -360,6 +360,7 @@
 	NET_IPV4_CONF_ARPFILTER=13,
 	NET_IPV4_CONF_MEDIUM_ID=14,
 	NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
+	NET_IPV4_CONF_ARP_ANNOUNCE=18,
 };
 
 /* /proc/sys/net/ipv4/netfilter */
diff -ur v2.4.25-rc2/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.4.25-rc2/linux/net/ipv4/arp.c	2003-11-28 22:04:14.000000000 +0200
+++ linux/net/ipv4/arp.c	2004-02-14 11:00:31.551794592 +0200
@@ -317,15 +317,40 @@
 
 static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
 {
-	u32 saddr;
+	u32 saddr = 0;
 	u8  *dst_ha = NULL;
 	struct net_device *dev = neigh->dev;
 	u32 target = *(u32*)neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
+	struct in_device *in_dev = in_dev_get(dev);
+
+	if (!in_dev)
+		return;
 
-	if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
+	switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
+	default:
+	case 0:		/* By default announce any local IP */
+		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;
-	else
+		if (inet_addr_type(saddr) == RTN_LOCAL) {
+			/* saddr should be known to target */
+			if (inet_addr_onlink(in_dev, target, saddr))
+				break;
+		}
+		saddr = 0;
+		break;
+	case 2:		/* Avoid secondary IPs, get a primary/preferred one */
+		break;
+	}
+
+	if (in_dev)
+		in_dev_put(in_dev);
+	if (!saddr)
 		saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
 
 	if ((probes -= neigh->parms->ucast_probes) < 0) {
diff -ur v2.4.25-rc2/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.4.25-rc2/linux/net/ipv4/devinet.c	2004-02-14 10:37:06.000000000 +0200
+++ linux/net/ipv4/devinet.c	2004-02-14 11:01:37.845716384 +0200
@@ -1057,7 +1057,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[18];
+	ctl_table devinet_vars[19];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -1106,6 +1106,9 @@
 	{NET_IPV4_CONF_ARPFILTER, "arp_filter",
 	 &ipv4_devconf.arp_filter, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
+	{NET_IPV4_CONF_ARP_ANNOUNCE, "arp_announce",
+	 &ipv4_devconf.arp_announce, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
 	{NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version",
 	 &ipv4_devconf.force_igmp_version, sizeof(int), 0644, NULL,
 	 &proc_dointvec},

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-14 12:03               ` Julian Anastasov
@ 2004-02-14 20:37                 ` David S. Miller
  0 siblings, 0 replies; 17+ messages in thread
From: David S. Miller @ 2004-02-14 20:37 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: netdev, linux-net

On Sat, 14 Feb 2004 14:03:06 +0200 (EET)
Julian Anastasov <ja@ssi.bg> wrote:

> On Fri, 13 Feb 2004, David S. Miller wrote:
> 
> > > http://www.ssi.bg/~ja/arp_announce-2.6.2-4.diff
> >
> > Ok, I eat this, please make a 2.4.x version against Marcelo's current tree.
> 
> 	Attached, against rc2 which looks enough.

Applying, thanks.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-12  4:22         ` David S. Miller
@ 2004-02-15 10:04           ` Julian Anastasov
  2004-02-18  3:07             ` David S. Miller
  0 siblings, 1 reply; 17+ messages in thread
From: Julian Anastasov @ 2004-02-15 10:04 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, linux-net


	Hello,

On Wed, 11 Feb 2004, David S. Miller wrote:

> The hidden patch does a hundred different things, that's what makes
> it so undigestable. :)
>
> Let us assume your arp_announce patch is applied.  Given that, plus the
> things you've mentioned, only a tiny piece of functionality is
> really needed from that hidden patch.
>
> Why don't you extract out just the needed part, and toss together
> an email with that patch explaining that specific behavior change?

	Appended is a patch for rich set of modes to ignore ARP
requests (yes Dave, I got your flag name :)). It is on top of the
arp_announce change. I hope, the main useful needs are represented,
all other modes belong to user space tools.

	As for the IPVS like setups they have two choices to use
arp_ignore combined with arp_announce:

- to define virtual IPs on different interface and to use
arp_ignore=1/2 and arp_announce=2

- or to use scope host IP addresses and to use arp_ignore=3 and
arp_announce=2. Such addresses can be used as preferred source
addresses in routes to talk with any remote host and at the same
time we achieve per IP filtering. By this way applications that
are not aware they are load balanced can use hidden addresses on
ARP devices if they need these addresses there.

	As for the performance, modes 1, 2 and 3 are slow, they
lookup for local IP addresses on one (mode 1 and 2) or all
interfaces (mode 3).

	The same patch is also here:

http://www.ssi.bg/~ja/tmp/arp_ignore-2.6.2-arp-1.diff

Regards

--
Julian Anastasov <ja@ssi.bg>

diff -ur v2.6.2-bk/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.6.2-bk/linux/Documentation/networking/ip-sysctl.txt	2004-02-14 14:12:55.000000000 +0200
+++ linux/Documentation/networking/ip-sysctl.txt	2004-02-14 23:06:40.000000000 +0200
@@ -530,6 +530,24 @@
 	receiving answer from the resolved target while decreasing
 	the level announces more valid sender's information.
 
+arp_ignore - INTEGER
+	Define different modes for sending replies in response to
+	received ARP requests that resolve local target IP addresses:
+	0 - (default): reply for any local target IP address, configured
+	on any interface
+	1 - reply only if the target IP address is local address
+	configured on the incoming interface
+	2 - reply only if the target IP address is local address
+	configured on the incoming interface and both with the
+	sender's IP address are part from same subnet on this interface
+	3 - do not reply for local addresses configured with scope host,
+	only resolutions for global and link addresses are replied
+	4-7 - reserved
+	8 - do not reply for all local addresses
+
+	The max value from conf/{all,interface}/arp_ignore is used
+	when ARP request is received on the {interface}
+
 tag - INTEGER
 	Allows you to write a number, which can be used as required.
 	Default value is 0.
diff -ur v2.6.2-bk/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.6.2-bk/linux/include/linux/inetdevice.h	2004-02-14 14:12:55.000000000 +0200
+++ linux/include/linux/inetdevice.h	2004-02-14 23:38:56.000000000 +0200
@@ -19,6 +19,7 @@
 	int	tag;
 	int     arp_filter;
 	int	arp_announce;
+	int	arp_ignore;
 	int	medium_id;
 	int	no_xfrm;
 	int	no_policy;
@@ -73,6 +74,7 @@
 
 #define IN_DEV_ARPFILTER(in_dev)	(ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
 #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))
 
 struct in_ifaddr
 {
@@ -99,6 +101,7 @@
 extern struct in_device *inetdev_init(struct net_device *dev);
 extern struct in_device	*inetdev_by_index(int);
 extern u32		inet_select_addr(const struct net_device *dev, u32 dst, int scope);
+extern u32		inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope);
 extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
 extern void		inet_forward_change(void);
 
diff -ur v2.6.2-bk/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.6.2-bk/linux/include/linux/sysctl.h	2004-02-14 14:12:55.000000000 +0200
+++ linux/include/linux/sysctl.h	2004-02-14 23:40:12.000000000 +0200
@@ -363,6 +363,7 @@
 	NET_IPV4_CONF_NOPOLICY=16,
 	NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
 	NET_IPV4_CONF_ARP_ANNOUNCE=18,
+	NET_IPV4_CONF_ARP_IGNORE=19,
 };
 
 /* /proc/sys/net/ipv4/netfilter */
diff -ur v2.6.2-bk/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.6.2-bk/linux/net/ipv4/arp.c	2004-02-14 14:12:55.000000000 +0200
+++ linux/net/ipv4/arp.c	2004-02-15 01:19:37.000000000 +0200
@@ -379,6 +379,42 @@
 		read_unlock_bh(&neigh->lock);
 }
 
+static int arp_ignore(struct in_device *in_dev, struct net_device *dev,
+		      u32 sip, u32 tip)
+{
+	int scope;
+
+	switch (IN_DEV_ARP_IGNORE(in_dev)) {
+	case 0:	/* Reply, the tip is already validated */
+		return 0;
+	case 1:	/* Reply only if tip is configured on the incoming interface */
+		sip = 0;
+		scope = RT_SCOPE_HOST;
+		break;
+	case 2:	/*
+		 * Reply only if tip is configured on the incoming interface
+		 * and is in same subnet as sip
+		 */
+		scope = RT_SCOPE_HOST;
+		break;
+	case 3:	/* Do not reply for scope host addresses */
+		sip = 0;
+		scope = RT_SCOPE_LINK;
+		dev = NULL;
+		break;
+	case 4:	/* Reserved */
+	case 5:
+	case 6:
+	case 7:
+		return 0;
+	case 8:	/* Do not reply */
+		return 1;
+	default:
+		return 0;
+	}
+	return !inet_confirm_addr(dev, sip, tip, scope);
+}
+
 static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
 {
 	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip,
@@ -789,7 +825,8 @@
 	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
 	if (sip == 0) {
 		if (arp->ar_op == htons(ARPOP_REQUEST) &&
-		    inet_addr_type(tip) == RTN_LOCAL)
+		    inet_addr_type(tip) == RTN_LOCAL &&
+		    !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;
 	}
@@ -804,7 +841,10 @@
 			n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 			if (n) {
 				int dont_send = 0;
-				if (IN_DEV_ARPFILTER(in_dev))
+
+				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); 
 				if (!dont_send)
 					arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
diff -ur v2.6.2-bk/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.6.2-bk/linux/net/ipv4/devinet.c	2004-02-14 14:12:55.000000000 +0200
+++ linux/net/ipv4/devinet.c	2004-02-15 11:46:20.380681736 +0200
@@ -809,6 +809,84 @@
 	goto out;
 }
 
+static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
+			      u32 local, int scope)
+{
+	int same = 0;
+	u32 addr = 0;
+
+	for_ifa(in_dev) {
+		if (!addr &&
+		    (local == ifa->ifa_local || !local) &&
+		    ifa->ifa_scope <= scope) {
+			addr = ifa->ifa_local;
+			if (same)
+				break;
+		}
+		if (!same) {
+			same = (!local || inet_ifa_match(local, ifa)) &&
+				(!dst || inet_ifa_match(dst, ifa));
+			if (same && addr) {
+				if (local || !dst)
+					break;
+				/* Is the selected addr into dst subnet? */
+				if (inet_ifa_match(addr, ifa))
+					break;
+				/* No, then can we use new local src? */
+				if (ifa->ifa_scope <= scope) {
+					addr = ifa->ifa_local;
+					break;
+				}
+				/* search for large dst subnet for addr */
+				same = 0;
+			}
+		}
+	} endfor_ifa(in_dev);
+
+	return same? addr : 0;
+}
+
+/*
+ * Confirm that local IP address exists using wildcards:
+ * - dev: only on this interface, 0=any interface
+ * - dst: only in the same subnet as dst, 0=any dst
+ * - local: address, 0=autoselect the local address
+ * - scope: maximum allowed scope value for the local address
+ */
+u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope)
+{
+	u32 addr = 0;
+	struct in_device *in_dev;
+
+	if (dev) {
+		read_lock(&inetdev_lock);
+		if ((in_dev = __in_dev_get(dev))) {
+			read_lock(&in_dev->lock);
+			addr = confirm_addr_indev(in_dev, dst, local, scope);
+			read_unlock(&in_dev->lock);
+		}
+		read_unlock(&inetdev_lock);
+
+		return addr;
+	}
+
+	read_lock(&dev_base_lock);
+	read_lock(&inetdev_lock);
+	for (dev = dev_base; dev; dev = dev->next) {
+		if ((in_dev = __in_dev_get(dev))) {
+			read_lock(&in_dev->lock);
+			addr = confirm_addr_indev(in_dev, dst, local, scope);
+			read_unlock(&in_dev->lock);
+			if (addr)
+				break;
+		}
+	}
+	read_unlock(&inetdev_lock);
+	read_unlock(&dev_base_lock);
+
+	return addr;
+}
+
 /*
  *	Device notifier
  */
@@ -1132,7 +1210,7 @@
 
 static struct devinet_sysctl_table {
 	struct ctl_table_header *sysctl_header;
-	ctl_table		devinet_vars[19];
+	ctl_table		devinet_vars[20];
 	ctl_table		devinet_dev[2];
 	ctl_table		devinet_conf_dir[2];
 	ctl_table		devinet_proto_dir[2];
@@ -1260,6 +1338,14 @@
 			.proc_handler	= &proc_dointvec,
 		},
 		{
+			.ctl_name	= NET_IPV4_CONF_ARP_IGNORE,
+			.procname	= "arp_ignore",
+			.data		= &ipv4_devconf.arp_ignore,
+			.maxlen		= sizeof(int),
+			.mode		= 0644,
+			.proc_handler	= &proc_dointvec,
+		},
+		{
 			.ctl_name	= NET_IPV4_CONF_NOXFRM,
 			.procname	= "disable_xfrm",
 			.data		= &ipv4_devconf.no_xfrm,

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-15 10:04           ` Julian Anastasov
@ 2004-02-18  3:07             ` David S. Miller
  2004-02-18  8:22               ` Julian Anastasov
  0 siblings, 1 reply; 17+ messages in thread
From: David S. Miller @ 2004-02-18  3:07 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: netdev, linux-net

On Sun, 15 Feb 2004 12:04:59 +0200 (EET)
Julian Anastasov <ja@ssi.bg> wrote:

> 	The same patch is also here:
> 
> http://www.ssi.bg/~ja/tmp/arp_ignore-2.6.2-arp-1.diff

I've applied this, the patch is a NOP unless people actually change
the sysctl value from the default.

This allows me to just put it in now, and we can refine the details of
the new behavior next.

Please make me a 2.4.x version of this patch (again with the other ARP
thing applied already).

Thanks Julian.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-18  3:07             ` David S. Miller
@ 2004-02-18  8:22               ` Julian Anastasov
  2004-02-18 21:03                 ` David S. Miller
  0 siblings, 1 reply; 17+ messages in thread
From: Julian Anastasov @ 2004-02-18  8:22 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, linux-net

[-- Attachment #1: Type: TEXT/PLAIN, Size: 490 bytes --]


	Hello,

On Tue, 17 Feb 2004, David S. Miller wrote:

> > http://www.ssi.bg/~ja/tmp/arp_ignore-2.6.2-arp-1.diff
>
> I've applied this, the patch is a NOP unless people actually change
> the sysctl value from the default.
>
> This allows me to just put it in now, and we can refine the details of
> the new behavior next.
>
> Please make me a 2.4.x version of this patch (again with the other ARP
> thing applied already).

	Thanks, it is attached.

Regards

--
Julian Anastasov <ja@ssi.bg>

[-- Attachment #2: arp_ignore for 2.4 --]
[-- Type: TEXT/PLAIN, Size: 7990 bytes --]

diff -ur v2.4.25-rc2-arp/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.4.25-rc2-arp/linux/Documentation/networking/ip-sysctl.txt	2004-02-18 09:55:12.000000000 +0200
+++ linux/Documentation/networking/ip-sysctl.txt	2004-02-18 09:58:20.611648280 +0200
@@ -512,6 +512,24 @@
 	receiving answer from the resolved target while decreasing
 	the level announces more valid sender's information.
 
+arp_ignore - INTEGER
+	Define different modes for sending replies in response to
+	received ARP requests that resolve local target IP addresses:
+	0 - (default): reply for any local target IP address, configured
+	on any interface
+	1 - reply only if the target IP address is local address
+	configured on the incoming interface
+	2 - reply only if the target IP address is local address
+	configured on the incoming interface and both with the
+	sender's IP address are part from same subnet on this interface
+	3 - do not reply for local addresses configured with scope host,
+	only resolutions for global and link addresses are replied
+	4-7 - reserved
+	8 - do not reply for all local addresses
+
+	The max value from conf/{all,interface}/arp_ignore is used
+	when ARP request is received on the {interface}
+
 tag - INTEGER
 	Allows you to write a number, which can be used as required.
 	Default value is 0.
diff -ur v2.4.25-rc2-arp/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.4.25-rc2-arp/linux/include/linux/inetdevice.h	2004-02-18 09:55:12.000000000 +0200
+++ linux/include/linux/inetdevice.h	2004-02-18 09:58:20.613647976 +0200
@@ -19,6 +19,7 @@
 	int	tag;
 	int     arp_filter;
 	int	arp_announce;
+	int	arp_ignore;
 	int	medium_id;
 	int	force_igmp_version;
 	void	*sysctl;
@@ -71,6 +72,7 @@
 
 #define IN_DEV_ARPFILTER(in_dev)	(ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
 #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))
 
 struct in_ifaddr
 {
@@ -97,6 +99,7 @@
 extern struct in_device *inetdev_init(struct net_device *dev);
 extern struct in_device	*inetdev_by_index(int);
 extern u32		inet_select_addr(const struct net_device *dev, u32 dst, int scope);
+extern u32		inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope);
 extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
 extern void		inet_forward_change(void);
 
diff -ur v2.4.25-rc2-arp/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.4.25-rc2-arp/linux/include/linux/sysctl.h	2004-02-18 09:55:12.000000000 +0200
+++ linux/include/linux/sysctl.h	2004-02-18 09:58:20.614647824 +0200
@@ -361,6 +361,7 @@
 	NET_IPV4_CONF_MEDIUM_ID=14,
 	NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
 	NET_IPV4_CONF_ARP_ANNOUNCE=18,
+	NET_IPV4_CONF_ARP_IGNORE=19,
 };
 
 /* /proc/sys/net/ipv4/netfilter */
diff -ur v2.4.25-rc2-arp/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.4.25-rc2-arp/linux/net/ipv4/arp.c	2004-02-18 09:55:12.000000000 +0200
+++ linux/net/ipv4/arp.c	2004-02-18 09:58:20.616647520 +0200
@@ -371,6 +371,42 @@
 		read_unlock_bh(&neigh->lock);
 }
 
+static int arp_ignore(struct in_device *in_dev, struct net_device *dev,
+		      u32 sip, u32 tip)
+{
+	int scope;
+
+	switch (IN_DEV_ARP_IGNORE(in_dev)) {
+	case 0:	/* Reply, the tip is already validated */
+		return 0;
+	case 1:	/* Reply only if tip is configured on the incoming interface */
+		sip = 0;
+		scope = RT_SCOPE_HOST;
+		break;
+	case 2:	/*
+		 * Reply only if tip is configured on the incoming interface
+		 * and is in same subnet as sip
+		 */
+		scope = RT_SCOPE_HOST;
+		break;
+	case 3:	/* Do not reply for scope host addresses */
+		sip = 0;
+		scope = RT_SCOPE_LINK;
+		dev = NULL;
+		break;
+	case 4:	/* Reserved */
+	case 5:
+	case 6:
+	case 7:
+		return 0;
+	case 8:	/* Do not reply */
+		return 1;
+	default:
+		return 0;
+	}
+	return !inet_confirm_addr(dev, sip, tip, scope);
+}
+
 static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
 {
 	struct rtable *rt;
@@ -781,7 +817,8 @@
 	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
 	if (sip == 0) {
 		if (arp->ar_op == htons(ARPOP_REQUEST) &&
-		    inet_addr_type(tip) == RTN_LOCAL)
+		    inet_addr_type(tip) == RTN_LOCAL &&
+		    !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;
 	}
@@ -796,7 +833,10 @@
 			n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 			if (n) {
 				int dont_send = 0;
-				if (IN_DEV_ARPFILTER(in_dev))
+
+				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); 
 				if (!dont_send)
 					arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
diff -ur v2.4.25-rc2-arp/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.4.25-rc2-arp/linux/net/ipv4/devinet.c	2004-02-18 09:55:12.000000000 +0200
+++ linux/net/ipv4/devinet.c	2004-02-18 09:59:34.675388880 +0200
@@ -772,6 +772,84 @@
 	return 0;
 }
 
+static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
+			      u32 local, int scope)
+{
+	int same = 0;
+	u32 addr = 0;
+
+	for_ifa(in_dev) {
+		if (!addr &&
+		    (local == ifa->ifa_local || !local) &&
+		    ifa->ifa_scope <= scope) {
+			addr = ifa->ifa_local;
+			if (same)
+				break;
+		}
+		if (!same) {
+			same = (!local || inet_ifa_match(local, ifa)) &&
+				(!dst || inet_ifa_match(dst, ifa));
+			if (same && addr) {
+				if (local || !dst)
+					break;
+				/* Is the selected addr into dst subnet? */
+				if (inet_ifa_match(addr, ifa))
+					break;
+				/* No, then can we use new local src? */
+				if (ifa->ifa_scope <= scope) {
+					addr = ifa->ifa_local;
+					break;
+				}
+				/* search for large dst subnet for addr */
+				same = 0;
+			}
+		}
+	} endfor_ifa(in_dev);
+
+	return same? addr : 0;
+}
+
+/*
+ * Confirm that local IP address exists using wildcards:
+ * - dev: only on this interface, 0=any interface
+ * - dst: only in the same subnet as dst, 0=any dst
+ * - local: address, 0=autoselect the local address
+ * - scope: maximum allowed scope value for the local address
+ */
+u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope)
+{
+	u32 addr = 0;
+	struct in_device *in_dev;
+
+	if (dev) {
+		read_lock(&inetdev_lock);
+		if ((in_dev = __in_dev_get(dev))) {
+			read_lock(&in_dev->lock);
+			addr = confirm_addr_indev(in_dev, dst, local, scope);
+			read_unlock(&in_dev->lock);
+		}
+		read_unlock(&inetdev_lock);
+
+		return addr;
+	}
+
+	read_lock(&dev_base_lock);
+	read_lock(&inetdev_lock);
+	for (dev = dev_base; dev; dev = dev->next) {
+		if ((in_dev = __in_dev_get(dev))) {
+			read_lock(&in_dev->lock);
+			addr = confirm_addr_indev(in_dev, dst, local, scope);
+			read_unlock(&in_dev->lock);
+			if (addr)
+				break;
+		}
+	}
+	read_unlock(&inetdev_lock);
+	read_unlock(&dev_base_lock);
+
+	return addr;
+}
+
 /*
  *	Device notifier
  */
@@ -1057,7 +1135,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[19];
+	ctl_table devinet_vars[20];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -1109,6 +1187,9 @@
 	{NET_IPV4_CONF_ARP_ANNOUNCE, "arp_announce",
 	 &ipv4_devconf.arp_announce, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
+	{NET_IPV4_CONF_ARP_IGNORE, "arp_ignore",
+	 &ipv4_devconf.arp_ignore, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
 	{NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version",
 	 &ipv4_devconf.force_igmp_version, sizeof(int), 0644, NULL,
 	 &proc_dointvec},

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Restrict local IP announcements in ARP requests
  2004-02-18  8:22               ` Julian Anastasov
@ 2004-02-18 21:03                 ` David S. Miller
  0 siblings, 0 replies; 17+ messages in thread
From: David S. Miller @ 2004-02-18 21:03 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: netdev, linux-net

On Wed, 18 Feb 2004 10:22:09 +0200 (EET)
Julian Anastasov <ja@ssi.bg> wrote:

> > Please make me a 2.4.x version of this patch (again with the other ARP
> > thing applied already).
> 
> 	Thanks, it is attached.

Applied.

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2004-02-18 21:03 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-02-08  9:59 Restrict local IP announcements in ARP requests Julian Anastasov
2004-02-09 22:08 ` David S. Miller
2004-02-09 22:20   ` David S. Miller
2004-02-09 23:06   ` Julian Anastasov
2004-02-09 23:10     ` David S. Miller
2004-02-10  0:31       ` Julian Anastasov
2004-02-12  4:22         ` David S. Miller
2004-02-15 10:04           ` Julian Anastasov
2004-02-18  3:07             ` David S. Miller
2004-02-18  8:22               ` Julian Anastasov
2004-02-18 21:03                 ` David S. Miller
2004-02-10  1:00       ` Julian Anastasov
2004-02-12  4:16         ` David S. Miller
2004-02-12 23:50           ` Julian Anastasov
2004-02-14  7:24             ` David S. Miller
2004-02-14 12:03               ` Julian Anastasov
2004-02-14 20:37                 ` David S. Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).