[PATCH] Netfilter hook for ARP

Tommi Virtanen tv-nospam-e2aac4@hq.yok.utu.fi
28 Jul 2001 09:48:21 +0300


--=-=-=

Brad Chapman <kakadu@earthlink.net> writes:

>    Due to a buggy e-mail tool, a portion of your patch was cut off. 
>    Did your

	Hmm, the copy I got from the list looks okay.
        Reattaching as MIME.

> patch also include new shared library protocol extensions for
> iptables and/or ip6tables, so that we can actually manipulate
> traffic in these hooks? AFAIK, the current protocol matches won't
> work for this low-level thing. This looks mildly interesting, but
> without the new extensions, no one will be able to do anything with
> it.

	Unfortunately I don't grok the userspace portion nearly as
	well. Hopefully someone else will step up. The reason I posted
	the patch was that someone mentioned he might be implementing
	it; no need for double work.


--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment; filename=netfilter-arp-246.patch
Content-Description: Netfilter ARP hooks for Linux 2.4.6

diff -Naur linux-2.4.6/include/linux/netfilter_arp.h linux/include/linux/netfilter_arp.h
--- linux-2.4.6/include/linux/netfilter_arp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/netfilter_arp.h	Tue Jul 10 11:03:33 2001
@@ -0,0 +1,15 @@
+#ifndef __LINUX_ARP_NETFILTER_H
+#define __LINUX_ARP_NETFILTER_H
+
+/* ARP-specific defines for netfilter. 
+ * Copyright 2000 Stonesoft Corp.
+ * Licensed under the GNU General Public License.
+ */
+
+#include <linux/netfilter.h>
+
+#define NF_ARP_IN	0
+#define NF_ARP_OUT	1
+#define NF_ARP_NUMHOOKS	2
+
+#endif /*__LINUX_ARP_NETFILTER_H*/
diff -Naur linux-2.4.6/net/ipv4/arp.c linux/net/ipv4/arp.c
--- linux-2.4.6/net/ipv4/arp.c	Wed May 16 20:21:45 2001
+++ linux/net/ipv4/arp.c	Tue Jul 10 11:04:16 2001
@@ -111,6 +111,8 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_arp.h>
 
 
 
@@ -562,7 +564,8 @@
 	memcpy(arp_ptr, &dest_ip, 4);
 	skb->dev = dev;
 
-	dev_queue_xmit(skb);
+	NF_HOOK(PF_UNSPEC, NF_ARP_OUT, skb, dev, NULL,
+                dev_queue_xmit);
 	return;
 
 out:
@@ -578,17 +581,16 @@
  *	Receive an arp request by the device layer.
  */
 
+static int arp_rcv2(struct sk_buff *skb);
+
 int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
 {
 	struct arphdr *arp = skb->nh.arph;
 	unsigned char *arp_ptr= (unsigned char *)(arp+1);
-	struct rtable *rt;
 	unsigned char *sha, *tha;
 	u32 sip, tip;
 	u16 dev_type = dev->type;
-	int addr_type;
 	struct in_device *in_dev = in_dev_get(dev);
-	struct neighbour *n;
 
 /*
  *	The hardware length of the packet should match the hardware length
@@ -739,6 +741,42 @@
  *  and in the case of requests for us we add the requester to the arp 
  *  cache.
  */
+        
+	if (in_dev)
+		in_dev_put(in_dev);
+	return NF_HOOK(PF_UNSPEC, NF_ARP_IN, skb, dev, NULL,
+		       arp_rcv2);
+
+ out:
+	if (in_dev)
+		in_dev_put(in_dev);
+ freeskb:
+	kfree_skb(skb);
+ out_of_mem:
+	return 0;
+}
+
+int arp_rcv2(struct sk_buff *skb) {
+	int addr_type;
+	struct rtable *rt;
+	struct neighbour *n;
+	struct arphdr *arp = skb->nh.arph;
+	unsigned char *arp_ptr= (unsigned char *)(arp+1);
+        struct net_device *dev = skb->dev;
+	struct in_device *in_dev = in_dev_get(dev);
+	unsigned char *sha, *tha;
+	u32 sip, tip;
+  
+/*
+ *	Extract fields
+ */
+	sha=arp_ptr;
+	arp_ptr += dev->addr_len;
+	memcpy(&sip, arp_ptr, 4);
+	arp_ptr += 4;
+	tha=arp_ptr;
+	arp_ptr += dev->addr_len;
+	memcpy(&tip, arp_ptr, 4);
 
 	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
 	if (sip == 0) {
@@ -747,7 +785,7 @@
 			arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);
 		goto out;
 	}
-
+        
 	if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
 	    ip_route_input(skb, tip, sip, 0, dev) == 0) {
 
@@ -768,7 +806,8 @@
 			goto out;
 		} else if (IN_DEV_FORWARD(in_dev)) {
 			if ((rt->rt_flags&RTCF_DNAT) ||
-			    (addr_type == RTN_UNICAST  && rt->u.dst.dev != dev &&
+			    ((addr_type == RTN_UNICAST || addr_type == RTN_BLACKHOLE || addr_type == RTN_UNREACHABLE)
+			     && rt->u.dst.dev != dev &&
 			     (IN_DEV_PROXY_ARP(in_dev) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
 				n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 				if (n)
@@ -828,9 +867,7 @@
 out:
 	if (in_dev)
 		in_dev_put(in_dev);
-freeskb:
 	kfree_skb(skb);
-out_of_mem:
 	return 0;
 }
 

--=-=-=


-- 
tv@{{hq.yok.utu,havoc,gaeshido}.fi,{debian,wanderer}.org,stonesoft.com}
double a,b=4,c;main(){for(;++a<2e6;c-=(b=-b)/a++);printf("%f\n",c);}

--=-=-=--