arp_filter patch for 2.4.4 kernel.
Subsystems (4)
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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]
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)) {
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".
Quoted 5 lines · dean gaudet
also -- isn't it kind of wrong for arp to respond with addresses from other interfaces?
what if
ip_forwardis 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]
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_forwardis 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
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?
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.
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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]
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
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]
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
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
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+(*)