Skip to contentSkip to conversation

arp_filter patch for 2.4.4 kernel.

PATCH In review Ben Greear 7 participants 15 messages May 5, 2001 – May 15, 2001

Subsystems (4)
lore
Share & tools
lore

Ben Greear

author
#0 lore raw

PATCH 1/1 arp_filter patch for 2.4.4 kernel.

This patch is ported from Andi Kleen's work for the 2.2.19 kernel (I think it was his, at least...)

It adds the ability to run multiple interfaces on the same subnet, on the same machine, and have the ARPs for each interface be answered based on whether or not the kernel would route a packet from the ARP'd IP out that interface. When used with source-based routing, this makes things work in an intuitive manner.

I find this a vital feature for one of my projects, and would welcome it's inclusion into the 2.4 kernel series!

The code seems to be working on my two test machines..

Thanks,
Ben

include/linux/inetdevice.h +4 -0
diff -u -r -N -X /home/greear/exclude.list linux/include/linux/inetdevice.h linux.dev/include/linux/inetdevice.h
@@ -17,6 +17,7 @@
 	int	forwarding;
 	int	mc_forwarding;
 	int	tag;
+        int     arp_filter;
 	void	*sysctl;
 };
 
@@ -53,6 +54,9 @@
 	  (ipv4_devconf.accept_redirects && (in_dev)->cnf.accept_redirects)) \
 	 || (!IN_DEV_FORWARD(in_dev) && \
 	  (ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects)))
+
+#define IN_DEV_ARPFILTER(in_dev)       (ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
+
 
 struct in_ifaddr
 {
include/linux/sysctl.h +2 -1
diff -u -r -N -X /home/greear/exclude.list linux/include/linux/sysctl.h linux.dev/include/linux/sysctl.h
@@ -324,7 +324,8 @@
 	NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9,
 	NET_IPV4_CONF_BOOTP_RELAY=10,
 	NET_IPV4_CONF_LOG_MARTIANS=11,
-	NET_IPV4_CONF_TAG=12
+	NET_IPV4_CONF_TAG=12,
+        NET_IPV4_CONF_ARPFILTER=13
 };
 
 /* /proc/sys/net/ipv6 */
include/net/snmp.h +2 -1
diff -u -r -N -X /home/greear/exclude.list linux/include/net/snmp.h linux.dev/include/net/snmp.h
@@ -198,7 +198,8 @@
 	unsigned long	RcvPruned;
 	unsigned long	OfoPruned;
 	unsigned long	OutOfWindowIcmps; 
-	unsigned long	LockDroppedIcmps; 
+	unsigned long	LockDroppedIcmps;
+        unsigned long   ArpFilter;
 	unsigned long	TimeWaited; 
 	unsigned long	TimeWaitRecycled; 
 	unsigned long	TimeWaitKilled; 
net/ipv4/arp.c +27 -1
diff -u -r -N -X /home/greear/exclude.list linux/net/ipv4/arp.c linux.dev/net/ipv4/arp.c
@@ -343,6 +343,26 @@
 		read_unlock_bh(&neigh->lock);
 }
 
+static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
+{
+       struct rtable *rt;
+       int flag = 0; 
+       /*unsigned long now; */
+
+       if (ip_route_output(&rt, sip, tip, 0, 0) < 0) 
+               return 1;
+       if (rt->u.dst.dev != dev) { 
+               /* TODO:  Figure out what this is supposed to do and re-insert it:
+                *
+                * net_statistics.ArpFilter++;
+                *
+                */
+               flag = 1; 
+       } 
+       ip_rt_put(rt); 
+       return flag; 
+} 
+
 /* OBSOLETE FUNCTIONS */
 
 /*
@@ -739,7 +759,13 @@
 		if (addr_type == RTN_LOCAL) {
 			n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 			if (n) {
-				arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+                                int dont_send = 0;
+                                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);
+                                }
 				neigh_release(n);
 			}
 			goto out;
net/ipv4/devinet.c +5 -2
diff -u -r -N -X /home/greear/exclude.list linux/net/ipv4/devinet.c linux.dev/net/ipv4/devinet.c
@@ -1016,7 +1016,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[13];
+	ctl_table devinet_vars[14];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -1059,7 +1059,10 @@
 	{NET_IPV4_CONF_TAG, "tag",
 	 &ipv4_devconf.tag, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
-	 {0}},
+        {NET_IPV4_CONF_ARPFILTER, "arp_filter",
+         &ipv4_devconf.arp_filter, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+        {0}},
 
 	{{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}},
 	{{NET_IPV4_CONF, "conf", NULL, 0, 0555, devinet_sysctl.devinet_dev},{0}},
net/ipv4/proc.c +1 -1
diff -u -r -N -X /home/greear/exclude.list linux/net/ipv4/proc.c linux.dev/net/ipv4/proc.c
@@ -170,7 +170,7 @@
 	len = sprintf(buffer,
 		      "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
 		      " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
-		      " OutOfWindowIcmps LockDroppedIcmps"
+		      " OutOfWindowIcmps LockDroppedIcmps ArpFilter"
 		      " TW TWRecycled TWKilled"
 		      " PAWSPassive PAWSActive PAWSEstab"
 		      " DelayedACKs DelayedACKLocked DelayedACKLost"
Signature · 3 lines
Ben Greear <[email protected]>          <[email protected]>
President of Candela Technologies Inc      http://www.candelatech.com
ScryMUD:  http://scry.wanfear.com     http://scry.wanfear.com/~greear
#1 lore raw
Quoted 8 lines · Ben Greear

This patch is ported from Andi Kleen's work for the 2.2.19 kernel (I think it was his, at least...)

It adds the ability to run multiple interfaces on the same subnet, on the same machine, and have the ARPs for each interface be answered based on whether or not the kernel would route a packet from the ARP'd IP out that interface. When used with source-based routing, this makes things work in an intuitive manner.

How difficult is it to compose netfilter rules that do this?

Later,
David S. Miller
[email protected]

#2 lore raw
Quoted 1 line · David S. Miller

How difficult is it to compose netfilter rules that do this?

what's the performance impact of doing that?

i've got multiple ip networks on the same gigabit link... i'm pretty happy with this tiny patch i've posted before, which is not on any critical path (it's in the ARP code after all).

-dean

net/ipv4/arp.c renamed from net/ipv4/arp.c.badproxy +2 -0
@@ -737,10 +737,12 @@
 		addr_type = rt->rt_type;
 
 		if (addr_type == RTN_LOCAL) {
+			if ((rt->rt_flags&RTCF_DIRECTSRC) || IN_DEV_PROXY_ARP(in_dev)) {
 			n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 			if (n) {
 				arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
 				neigh_release(n);
+			}
 			}
 			goto out;
 		} else if (IN_DEV_FORWARD(in_dev)) {
#3 lore raw

also -- isn't it kind of wrong for arp to respond with addresses from other interfaces?

what if ip_forward is 0? or if there's some other sort of routing policy in effect?

-dean

Quoted 1 line · dean gaudet

i've got multiple ip networks on the same gigabit link...

p.s. that should have read "on the same gigabit switch".

#4 lore raw
Quoted 5 lines · dean gaudet

also -- isn't it kind of wrong for arp to respond with addresses from other interfaces?

what if ip_forward is 0? or if there's some other sort of routing policy in effect?

This along with some other issues are why Alexey and myself want to do ARP filter in some other way.

There are two sides to this story though, both with valid arguments.

Ho hum... since things have settled down in the networking and this is being pushed again, I guess it's time to fire up the dialogue once more.

Later,
David S. Miller
[email protected]

#5 lore raw
In reply to dean gaudet
Quoted 2 lines · dean gaudet

also -- isn't it kind of wrong for arp to respond with addresses from other interfaces?

Usually it makes sense, because it increases your chances of successfull communication. IP addresses are owned by the complete host on Linux, not by different interfaces.

For some weirder setups (most of them just caused by incorrect routing tables, but also a few legimitate ones; including incoming load balancing via multipath routes) it causes problems, so arpfilter was invented to sync ARP replies with the routing tables as needed.

Quoted 3 lines

what if ip_forward is 0? or if there's some other sort of routing policy in effect?

ARP filter has nothing to do with forwarding.

There is magic ARP proxying if linux knows the answer to an ARP request on a different interface, but it's a completely independent thing.

-Andi

#6 lore raw
Quoted 6 lines
Quoted 2 lines

also -- isn't it kind of wrong for arp to respond with addresses from other interfaces?

Usually it makes sense, because it increases your chances of successfull communication. IP addresses are owned by the complete host on Linux, not by different interfaces.

this is one of those things that is still hurting Linux's credibility in the read world. people see this kind of obviously broken behavior, and install *BSD or Solaris instead.

isn't this clearly a case of the kernel being too smart: making it impossible for a clueful admin to do what he needs? multi-nic machines are now quite common, but this "feature" makes them far less useful, since the stack is violating the admin's intention.

Quoted 4 lines

For some weirder setups (most of them just caused by incorrect routing tables, but also a few legimitate ones; including incoming load balancing via multipath routes) it causes problems, so arpfilter was invented to sync ARP replies with the routing tables as needed.

there's NOTHING weird about a machine having two nics and two IPs, wanting to behave like two hosts.

is there any positive/beneficial reason for the current behavior?

#7 lore raw
In reply to David S. Miller
Quoted 7 lines · David S. Miller
Quoted 5 lines

It adds the ability to run multiple interfaces on the same subnet, on the same machine, and have the ARPs for each interface be answered based on whether or not the kernel would route a packet from the ARP'd IP out that interface. When used with source-based routing, this makes things work in an intuitive manner.

How difficult is it to compose netfilter rules that do this?

I want this feature precisely /because/ it interferes with packet filtering.

I sleep better knowing that my packet filters are bound to specific interfaces (with default DENY everywhere). I like to know that I can ssh in via the second card on my DB servers, without worrying about them accepting other traffic (or performance-vital traffic going over a cheap backup card).

Matthew.

author
#8 lore raw
Quoted 9 lines · Matthew Kirkwood
Quoted 6 lines · David S. Miller
Quoted 5 lines

It adds the ability to run multiple interfaces on the same subnet, on the same machine, and have the ARPs for each interface be answered based on whether or not the kernel would route a packet from the ARP'd IP out that interface. When used with source-based routing, this makes things work in an intuitive manner.

Quoted 4 lines
Quoted 1 line

How difficult is it to compose netfilter rules that do this?

I want this feature precisely /because/ it interferes with packet filtering.

It looks like several people, including me, like this patch, or at least a similar patch. This patch would also add a feature to the 2.4 series that is missing, with regard to the 2.2.19 kernel. If it was good enough for 2.2.19, shouldn't it be good enough for 2.4?

If anyone has any particular gripes about the patch, lets see if we can work them out instead of just letting the topic drown silently in the flood of LK.

I'm re-attaching the patch in case that helps.....

diff -u -r -N -X /home/greear/exclude.list linux/include/linux/inetdevice.h linux.dev/include/linux/inetdevice.h

include/linux/inetdevice.h +4 -0
@@ -17,6 +17,7 @@
 	int	forwarding;
 	int	mc_forwarding;
 	int	tag;
+        int     arp_filter;
 	void	*sysctl;
 };
 
@@ -53,6 +54,9 @@
 	  (ipv4_devconf.accept_redirects && (in_dev)->cnf.accept_redirects)) \
 	 || (!IN_DEV_FORWARD(in_dev) && \
 	  (ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects)))
+
+#define IN_DEV_ARPFILTER(in_dev)       (ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
+
 
 struct in_ifaddr
 {
include/linux/sysctl.h +2 -1
diff -u -r -N -X /home/greear/exclude.list linux/include/linux/sysctl.h linux.dev/include/linux/sysctl.h
@@ -324,7 +324,8 @@
 	NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9,
 	NET_IPV4_CONF_BOOTP_RELAY=10,
 	NET_IPV4_CONF_LOG_MARTIANS=11,
-	NET_IPV4_CONF_TAG=12
+	NET_IPV4_CONF_TAG=12,
+        NET_IPV4_CONF_ARPFILTER=13
 };
 
 /* /proc/sys/net/ipv6 */
include/net/snmp.h +2 -1
diff -u -r -N -X /home/greear/exclude.list linux/include/net/snmp.h linux.dev/include/net/snmp.h
@@ -198,7 +198,8 @@
 	unsigned long	RcvPruned;
 	unsigned long	OfoPruned;
 	unsigned long	OutOfWindowIcmps; 
-	unsigned long	LockDroppedIcmps; 
+	unsigned long	LockDroppedIcmps;
+        unsigned long   ArpFilter;
 	unsigned long	TimeWaited; 
 	unsigned long	TimeWaitRecycled; 
 	unsigned long	TimeWaitKilled; 
net/ipv4/arp.c +27 -1
diff -u -r -N -X /home/greear/exclude.list linux/net/ipv4/arp.c linux.dev/net/ipv4/arp.c
@@ -343,6 +343,26 @@
 		read_unlock_bh(&neigh->lock);
 }
 
+static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
+{
+       struct rtable *rt;
+       int flag = 0; 
+       /*unsigned long now; */
+
+       if (ip_route_output(&rt, sip, tip, 0, 0) < 0) 
+               return 1;
+       if (rt->u.dst.dev != dev) { 
+               /* TODO:  Figure out what this is supposed to do and re-insert it:
+                *
+                * net_statistics.ArpFilter++;
+                *
+                */
+               flag = 1; 
+       } 
+       ip_rt_put(rt); 
+       return flag; 
+} 
+
 /* OBSOLETE FUNCTIONS */
 
 /*
@@ -739,7 +759,13 @@
 		if (addr_type == RTN_LOCAL) {
 			n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 			if (n) {
-				arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+                                int dont_send = 0;
+                                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);
+                                }
 				neigh_release(n);
 			}
 			goto out;
net/ipv4/devinet.c +5 -2
diff -u -r -N -X /home/greear/exclude.list linux/net/ipv4/devinet.c linux.dev/net/ipv4/devinet.c
@@ -1016,7 +1016,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[13];
+	ctl_table devinet_vars[14];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -1059,7 +1059,10 @@
 	{NET_IPV4_CONF_TAG, "tag",
 	 &ipv4_devconf.tag, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
-	 {0}},
+        {NET_IPV4_CONF_ARPFILTER, "arp_filter",
+         &ipv4_devconf.arp_filter, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+        {0}},
 
 	{{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}},
 	{{NET_IPV4_CONF, "conf", NULL, 0, 0555, devinet_sysctl.devinet_dev},{0}},
net/ipv4/proc.c +1 -1
diff -u -r -N -X /home/greear/exclude.list linux/net/ipv4/proc.c linux.dev/net/ipv4/proc.c
@@ -170,7 +170,7 @@
 	len = sprintf(buffer,
 		      "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
 		      " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
-		      " OutOfWindowIcmps LockDroppedIcmps"
+		      " OutOfWindowIcmps LockDroppedIcmps ArpFilter"
 		      " TW TWRecycled TWKilled"
 		      " PAWSPassive PAWSActive PAWSEstab"
 		      " DelayedACKs DelayedACKLocked DelayedACKLost"

Thanks,
Ben

Signature · 3 lines
Ben Greear <[email protected]>          <[email protected]>
President of Candela Technologies Inc      http://www.candelatech.com
ScryMUD:  http://scry.wanfear.com     http://scry.wanfear.com/~greear
#9 lore raw
Quoted 2 lines · Ben Greear

If it was good enough for 2.2.19, shouldn't it be good enough for 2.4?

Actually, by itself, this is a bogus argument. Many things in 2.2.x have been explicitly removed in 2.4.x :-)

Regardless, the arp filter in some form will be added. Don't worry.

Later,
David S. Miller
[email protected]

author
#10 lore raw
In reply to Ben Greear
Quoted 5 lines · David S. Miller
Quoted 3 lines · Ben Greear

This patch is ported from Andi Kleen's work for the 2.2.19 kernel (I think it was his, at least...)

Quoted 7 lines
Quoted 5 lines

It adds the ability to run multiple interfaces on the same subnet, on the same machine, and have the ARPs for each interface be answered based on whether or not the kernel would route a packet from the ARP'd IP out that interface. When used with source-based routing, this makes things work in an intuitive manner.

How difficult is it to compose netfilter rules that do this?

No idea, haven't tried to use netfilter. With this patch, though, it's as easy as:

echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter

I have a setup that should be able to test some netfilter rules if have some you want me to try....

Thanks,
Ben

Signature · 3 lines
Ben Greear <[email protected]>          <[email protected]>
President of Candela Technologies Inc      http://www.candelatech.com
ScryMUD:  http://scry.wanfear.com     http://scry.wanfear.com/~greear
#11 lore raw
Quoted 2 lines · Ben Greear

No idea, haven't tried to use netfilter. With this patch, though, it's as easy as:

I know, the problem is if some existing facility can be made to do it, I'd rather it be done that way.

Quoted 2 lines

I have a setup that should be able to test some netfilter rules if have some you want me to try....

I'd be interested in seeing netfilter rules or a new netfilter kernel module which would do arpfilter as well.

Later,
David S. Miller
[email protected]

author
#12 lore raw
In reply to Ben Greear
Quoted 7 lines · David S. Miller
Quoted 2 lines · Ben Greear

No idea, haven't tried to use netfilter. With this patch, though, it's as easy as:

I know, the problem is if some existing facility can be made to do it, I'd rather it be done that way.

Would requiring netfilter to be used slow down the fast path for packets in any way? The current arp-filter code will not, as far as I can tell, and if the netfilter overhead is significant, that may be a good reason to accept the patch, or the alternative one proposed a few mails back...

Signature · 3 lines
Ben Greear <[email protected]>          <[email protected]>
President of Candela Technologies Inc      http://www.candelatech.com
ScryMUD:  http://scry.wanfear.com     http://scry.wanfear.com/~greear
#13 lore raw
In reply to Ben Greear
Quoted 5 lines · David S. Miller
Quoted 2 lines

I have a setup that should be able to test some netfilter rules if have some you want me to try....

I'd be interested in seeing netfilter rules or a new netfilter kernel module which would do arpfilter as well.

I don't think it's a good idea. You either need a lot of hooks in the arp input path for all the different cases or you would need to replicate a lot of the arp.c logic into that netfilter module. Both not good. IMHO it's better to just control replies via the routing table, which already has all kinds of fancy mechanisms for it. In addition I haven't seen a setup yet that couldn't be handled by arpfilter and the routing table, it seems to be flexible enough for all practical purposes.

-Andi

#14 lore raw
In reply to Ben Greear
Quoted 5 lines · David Miller
Quoted 2 lines

No idea, haven't tried to use netfilter. With this patch, though, it's as easy as:

I know, the problem is if some existing facility can be made to do it, I'd rather it be done that way.

of course.

Quoted 2 lines

I'd be interested in seeing netfilter rules or a new netfilter kernel module which would do arpfilter as well.

the problem is, that netfilter hooks are currently only in the IPv4 and IPv6 packet paths. as ARP is not an IPv4 protocol, but another protocol residing at layer 3, the arp code bypasses all netfilter hooks, and is - as a result - not handled by any IP tables.

If you would want to do it using netfilter (the hooks only) and a hook- attaching module, you need to add ARP netfilter hooks first.

If you want to filter arp packets, you need the netfilter hooks in the ARP code, as well as a new 'arptables' module and a userspace tool allowing modification of those arp tables.

So I see no clean solution for using netfilter in this case. It's one of the scenario where netfilter/iptables layer-three-protocol boundness hurts.

Quoted 1 line

David S. Miller

Signature · 5 lines
Live long and prosper
- Harald Welte / [email protected]                http://www.gnumonks.org
============================================================================
GCS/E/IT d- s-: a-- C+++ UL++++$ P+++ L++++$ E--- W- N++ o? K- w--- O- M- 
V-- PS+ PE-- Y+ PGP++ t++ 5-- !X !R tv-- b+++ DI? !D G+ e* h+ r% y+(*)