netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Netfilter crossover module.
@ 2003-07-10  8:47 Rusty Russell
  2003-07-10 14:06 ` James R. Leu
  0 siblings, 1 reply; 3+ messages in thread
From: Rusty Russell @ 2003-07-10  8:47 UTC (permalink / raw)
  To: netdev; +Cc: netfilter-devel, anton

Lots of people keep asking to be able to plug a crossover cables
between to NICs in a machine, and use it for testing.

This is a simple module which does this, by creating phantom
machine(s) on each network with IP address 1 greater than the
interface.  Testers welcome.

Ignore the backwards compat crap, it'll be out of the final version.

Example usage:
  # Bring interfaces up
  ifconfig eth0 192.168.1.1
  ifconfig eth1 192.168.2.1

  # Add module which creates "phantom" machines 192.168.1.2, and 192.168.2.2.
  modprobe ip_crossover dev1=eth0 dev2=eth1

  # Tell kernel that 192.168.1.2 packets go to eth1, and .2.1 to eth0.
  arp -s 192.168.1.2 <hardware address of eth1>
  arp -s 192.168.2.2 <hardware address of eth0>

It'd be nice to have the module hardwire the arps itself, but this was
quickest.  Patch welcome.

Rusty.

Name: Hardware Loopback Module
Author: Rusty Russell
Status: Tested on 2.5.74-bk5

D: For testing it is often nice to connect two NICs with a crossover
D: cable and have the machine route packets between them.
D: 
D: Since Linux steadfastly regards IP addresses as properties of the
D: box, not the individual NICs, this requires some trickery.  A simple
D: netfilter module makes this possible, by producing "phantom" boxes.

diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.74-bk5/net/ipv4/netfilter/Kconfig working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/Kconfig
--- linux-2.5.74-bk5/net/ipv4/netfilter/Kconfig	2003-07-03 09:44:02.000000000 +1000
+++ working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/Kconfig	2003-07-08 18:03:29.000000000 +1000
@@ -587,5 +587,18 @@ config IP_NF_COMPAT_IPFWADM
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+config IP_NF_CROSSOVER
+	tristate "IP forced crossover support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  This option allows you to connect two local network cards
+	  with a crossover cable, and then force packets to pass over
+	  that cable (Linux will normally short-circuit such packets).
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>: the module will be called
+	  ip_crossover.
+
+	  Say `N'.
 endmenu
 
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.74-bk5/net/ipv4/netfilter/Makefile working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/Makefile
--- linux-2.5.74-bk5/net/ipv4/netfilter/Makefile	2003-07-03 09:44:02.000000000 +1000
+++ working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/Makefile	2003-07-08 18:03:29.000000000 +1000
@@ -92,3 +92,5 @@ obj-$(CONFIG_IP_NF_COMPAT_IPCHAINS) += i
 obj-$(CONFIG_IP_NF_COMPAT_IPFWADM) += ipfwadm.o
 
 obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
+
+obj-$(CONFIG_IP_NF_CROSSOVER) += ip_crossover.o
diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.74-bk5/net/ipv4/netfilter/ip_crossover.c working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/ip_crossover.c
--- linux-2.5.74-bk5/net/ipv4/netfilter/ip_crossover.c	1970-01-01 10:00:00.000000000 +1000
+++ working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/ip_crossover.c	2003-07-10 18:04:59.000000000 +1000
@@ -0,0 +1,257 @@
+/* Copyright 2003 Rusty Russell, IBM Corporation.
+ * 
+ * Simple packet mangling.  The idea is to use a crossover between two
+ * local NICs for testing, then this module creates "phantom" boxes on
+ * each network at the interface address + 1.
+ *
+ * Packets sent to one phantom will come in like they came from the other.
+ *
+ * Usage:
+ *   ifconfig eth0 192.168.1.1
+ *   ifconfig eth1 192.168.2.1
+ *   arp -s 192.168.1.2 <hardware address of eth1>
+ *   arp -s 192.168.2.2 <hardware address of eth2>
+ *   modprobe ip_crossover dev1=eth0 dev2=eth1
+ *
+ *   Then doing ping 192.168.1.2, ICMP ping goes out eth0 and comes
+ *   back in eth1.  Reply goes out eth1 and comes back in eth0.  */
+#include <linux/config.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/moduleparam.h>
+#include <linux/inetdevice.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/icmp.h>
+#include <linux/version.h>
+#include <net/ip.h>
+#include <asm/checksum.h>
+
+struct ifinfo
+{
+	/* Keep track of name so we can drop reference. */
+	char name[IFNAMSIZ];
+
+	/* Cached interface addr. */
+	u32 ifaddr;
+
+	/* "Phantom" box which gets mapped. */
+	u32 phantom;
+};
+
+static struct ifinfo devinfo1, devinfo2;
+
+/* Stolen from Alexey's ip_nat_dumb. */
+static int nat_header(struct sk_buff *skb, u32 saddr, u32 daddr)
+{
+	struct iphdr *iph = skb->nh.iph;
+
+	u32 odaddr = iph->daddr;
+	u32 osaddr = iph->saddr;
+	u16 check;
+
+	/* Rewrite IP header */
+	iph->saddr = saddr;
+	iph->daddr = daddr;
+	iph->check = 0;
+	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+	/* If it is the first fragment, rewrite protocol headers */
+	if (!(iph->frag_off & htons(IP_OFFSET))) {
+		u16 *cksum;
+
+		switch(iph->protocol) {
+		case IPPROTO_TCP:
+			cksum  = (u16*)&((struct tcphdr*)
+					 (((char*)iph)+(iph->ihl<<2)))->check;
+			if ((u8*)(cksum+1) > skb->tail)
+				return 0;
+			check = *cksum;
+			if (skb->ip_summed != CHECKSUM_HW)
+				check = ~check;
+			check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+						  0, 0, check);
+			check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0,
+						  ~check);
+			if (skb->ip_summed == CHECKSUM_HW)
+				check = ~check;
+			*cksum = check;
+			break;
+		case IPPROTO_UDP:
+			cksum  = (u16*)&((struct udphdr*)
+					 (((char*)iph)+(iph->ihl<<2)))->check;
+			if ((u8*)(cksum+1) > skb->tail)
+				return 0;
+			if ((check = *cksum) != 0) {
+				check = csum_tcpudp_magic(iph->saddr, 
+							  iph->daddr, 0, 0,
+							  ~check);
+				check = csum_tcpudp_magic(~osaddr, ~odaddr,
+							  0, 0, ~check);
+				*cksum = check ? : 0xFFFF;
+			}
+			break;
+		case IPPROTO_ICMP:
+		{
+			struct icmphdr *icmph
+				= (struct icmphdr*)((char*)iph+(iph->ihl<<2));
+			struct iphdr *ciph;
+			u32 idaddr, isaddr;
+
+			if ((icmph->type != ICMP_DEST_UNREACH) &&
+			    (icmph->type != ICMP_TIME_EXCEEDED) &&
+			    (icmph->type != ICMP_PARAMETERPROB))
+				break;
+
+			ciph = (struct iphdr *) (icmph + 1);
+
+			if ((u8*)(ciph+1) > skb->tail)
+				return 0;
+
+			isaddr = ciph->saddr;
+			idaddr = ciph->daddr;
+
+			/* Change addresses inside ICMP packet. */
+			ciph->daddr = iph->saddr;
+			ciph->saddr = iph->daddr;
+			cksum  = &icmph->checksum;
+			/* Using tcpudp primitive. Why not? */
+			check  = csum_tcpudp_magic(ciph->saddr, ciph->daddr,
+						   0, 0, ~(*cksum));
+			*cksum = csum_tcpudp_magic(~isaddr, ~idaddr, 0, 0,
+						   ~check);
+			break;
+		}
+		default:
+			break;
+		}
+	}
+	return 1;
+}
+
+static unsigned int xover_hook(unsigned int hook,
+			       struct sk_buff **pskb,
+			       const struct net_device *in,
+			       const struct net_device *out,
+			       int (*okfn)(struct sk_buff *))
+{
+	/* Going out to phantom box 1: change it to coming from
+           phantom box 2, and vice versa. */
+	if ((*pskb)->nh.iph->daddr == devinfo1.phantom) {
+		printk(KERN_DEBUG "dev1: %u.%u.%u.%u->%u.%u.%u.%u"
+		       " becomes %u.%u.%u.%u->%u.%u.%u.%u\n",
+		       NIPQUAD((*pskb)->nh.iph->saddr),
+		       NIPQUAD((*pskb)->nh.iph->daddr),
+		       NIPQUAD(devinfo2.phantom),
+		       NIPQUAD(devinfo2.ifaddr));
+		if (!nat_header(*pskb, devinfo2.phantom, devinfo2.ifaddr))
+			return NF_DROP;
+	} else if ((*pskb)->nh.iph->daddr == devinfo2.phantom) {
+		printk(KERN_DEBUG "dev1: %u.%u.%u.%u->%u.%u.%u.%u"
+		       " becomes %u.%u.%u.%u->%u.%u.%u.%u\n",
+		       NIPQUAD((*pskb)->nh.iph->saddr),
+		       NIPQUAD((*pskb)->nh.iph->daddr),
+		       NIPQUAD(devinfo1.phantom),
+		       NIPQUAD(devinfo1.ifaddr));
+		if (!nat_header(*pskb, devinfo1.phantom, devinfo1.ifaddr))
+			return NF_DROP;
+	}
+
+	return NF_ACCEPT;
+}
+
+static struct nf_hook_ops xover_ops
+= { .hook = xover_hook,
+    .owner = THIS_MODULE,
+    .pf = PF_INET,
+    .hooknum = NF_IP_POST_ROUTING, 
+    .priority = NF_IP_PRI_MANGLE,
+};
+
+static int __set_dev(const char *name, struct ifinfo *ifi)
+{
+	struct net_device *dev;
+	struct in_device *indev;
+
+	dev = dev_get_by_name(name);
+	if (!dev)
+		goto fail;
+	indev = __in_dev_get(dev);
+	if (!indev || !indev->ifa_list)
+		goto put_fail;
+
+	ifi->ifaddr = indev->ifa_list->ifa_address;
+	ifi->phantom = htonl(ntohl(indev->ifa_list->ifa_address) + 1);
+	if (ifi->phantom == indev->ifa_list->ifa_broadcast)
+		goto put_fail;
+
+	strlcpy(ifi->name, name, sizeof(ifi->name));
+	printk(KERN_INFO "ip_crossover: phantom for %s: %u.%u.%u.%u\n",
+	       ifi->name, NIPQUAD(ifi->phantom));
+	return 0;
+
+put_fail:
+	dev_put(dev);
+fail:
+	printk(KERN_WARNING "ip_crossover: device %s is not usable.\n", name);
+	return -ENOENT;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,50)
+static int set_dev(const char *val, struct kernel_param *kp)
+{
+	return __set_dev(val, kp->arg);
+}
+module_param_call(dev1, set_dev, NULL, &devinfo1, 0);
+module_param_call(dev2, set_dev, NULL, &devinfo2, 0);
+
+#define compat_parse_params()
+#else
+static char *dev1, *dev2;
+
+MODULE_PARM(dev1, "s");
+MODULE_PARM(dev2, "s");
+
+static void compat_parse_params(void)
+{
+	if (dev1)
+		__set_dev(dev1, &devinfo1);
+	if (dev2)
+		__set_dev(dev2, &devinfo2);
+}
+#endif /* KERNEL_VERSION */
+
+static int __init init(void)
+{
+	compat_parse_params();
+
+	if (!devinfo1.name[0] || !devinfo2.name[0]) {
+		printk(KERN_ERR "ip_crossover: need dev1 and dev2 args\n");
+		return -EINVAL;
+	}
+
+	return nf_register_hook(&xover_ops);
+}
+
+static void __exit fini(void)
+{
+	struct net_device *dev;
+
+	nf_unregister_hook(&xover_ops);
+
+	/* Release devices. */
+	dev = dev_get_by_name(devinfo1.name);
+	dev_put(dev);
+	dev_put(dev);
+
+	dev = dev_get_by_name(devinfo2.name);
+	dev_put(dev);
+	dev_put(dev);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(dev1, "First device for crossover (required)");
+MODULE_PARM_DESC(dev2, "Second device for crossover (required)");

--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

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

* Re: [PATCH] Netfilter crossover module.
  2003-07-10  8:47 [PATCH] Netfilter crossover module Rusty Russell
@ 2003-07-10 14:06 ` James R. Leu
  2003-07-10 16:52   ` Ben Greear
  0 siblings, 1 reply; 3+ messages in thread
From: James R. Leu @ 2003-07-10 14:06 UTC (permalink / raw)
  To: Rusty Russell; +Cc: netdev, netfilter-devel, anton

Between you and Ben Greear the linux kernel will have every possible
scheme for sending packets to your self.

I still think my work on this (Virtual routing and forwarding:
http://linux-vrf.sf.net/) is the less perverted(*) then the work that either
you or Ben have come up with.  Plus it has other applications besides
just being able to send packets to your self.

* in terms of the concept, not necessarily the actual implementation.

On Thu, Jul 10, 2003 at 06:47:05PM +1000, Rusty Russell wrote:
> Lots of people keep asking to be able to plug a crossover cables
> between to NICs in a machine, and use it for testing.
> 
> This is a simple module which does this, by creating phantom
> machine(s) on each network with IP address 1 greater than the
> interface.  Testers welcome.
> 
> Ignore the backwards compat crap, it'll be out of the final version.
> 
> Example usage:
>   # Bring interfaces up
>   ifconfig eth0 192.168.1.1
>   ifconfig eth1 192.168.2.1
> 
>   # Add module which creates "phantom" machines 192.168.1.2, and 192.168.2.2.
>   modprobe ip_crossover dev1=eth0 dev2=eth1
> 
>   # Tell kernel that 192.168.1.2 packets go to eth1, and .2.1 to eth0.
>   arp -s 192.168.1.2 <hardware address of eth1>
>   arp -s 192.168.2.2 <hardware address of eth0>
> 
> It'd be nice to have the module hardwire the arps itself, but this was
> quickest.  Patch welcome.
> 
> Rusty.
> 
> Name: Hardware Loopback Module
> Author: Rusty Russell
> Status: Tested on 2.5.74-bk5
> 
> D: For testing it is often nice to connect two NICs with a crossover
> D: cable and have the machine route packets between them.
> D: 
> D: Since Linux steadfastly regards IP addresses as properties of the
> D: box, not the individual NICs, this requires some trickery.  A simple
> D: netfilter module makes this possible, by producing "phantom" boxes.
> 
> diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.74-bk5/net/ipv4/netfilter/Kconfig working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/Kconfig
> --- linux-2.5.74-bk5/net/ipv4/netfilter/Kconfig	2003-07-03 09:44:02.000000000 +1000
> +++ working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/Kconfig	2003-07-08 18:03:29.000000000 +1000
> @@ -587,5 +587,18 @@ config IP_NF_COMPAT_IPFWADM
>  	  If you want to compile it as a module, say M here and read
>  	  <file:Documentation/modules.txt>.  If unsure, say `N'.
>  
> +config IP_NF_CROSSOVER
> +	tristate "IP forced crossover support (EXPERIMENTAL)"
> +	depends on EXPERIMENTAL
> +	help
> +	  This option allows you to connect two local network cards
> +	  with a crossover cable, and then force packets to pass over
> +	  that cable (Linux will normally short-circuit such packets).
> +
> +	  If you want to compile it as a module, say M here and read
> +	  <file:Documentation/modules.txt>: the module will be called
> +	  ip_crossover.
> +
> +	  Say `N'.
>  endmenu
>  
> diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.74-bk5/net/ipv4/netfilter/Makefile working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/Makefile
> --- linux-2.5.74-bk5/net/ipv4/netfilter/Makefile	2003-07-03 09:44:02.000000000 +1000
> +++ working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/Makefile	2003-07-08 18:03:29.000000000 +1000
> @@ -92,3 +92,5 @@ obj-$(CONFIG_IP_NF_COMPAT_IPCHAINS) += i
>  obj-$(CONFIG_IP_NF_COMPAT_IPFWADM) += ipfwadm.o
>  
>  obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
> +
> +obj-$(CONFIG_IP_NF_CROSSOVER) += ip_crossover.o
> diff -urNp --exclude TAGS -X /home/rusty/current-dontdiff --minimal linux-2.5.74-bk5/net/ipv4/netfilter/ip_crossover.c working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/ip_crossover.c
> --- linux-2.5.74-bk5/net/ipv4/netfilter/ip_crossover.c	1970-01-01 10:00:00.000000000 +1000
> +++ working-2.5.74-bk5-hardware_loopback/net/ipv4/netfilter/ip_crossover.c	2003-07-10 18:04:59.000000000 +1000
> @@ -0,0 +1,257 @@
> +/* Copyright 2003 Rusty Russell, IBM Corporation.
> + * 
> + * Simple packet mangling.  The idea is to use a crossover between two
> + * local NICs for testing, then this module creates "phantom" boxes on
> + * each network at the interface address + 1.
> + *
> + * Packets sent to one phantom will come in like they came from the other.
> + *
> + * Usage:
> + *   ifconfig eth0 192.168.1.1
> + *   ifconfig eth1 192.168.2.1
> + *   arp -s 192.168.1.2 <hardware address of eth1>
> + *   arp -s 192.168.2.2 <hardware address of eth2>
> + *   modprobe ip_crossover dev1=eth0 dev2=eth1
> + *
> + *   Then doing ping 192.168.1.2, ICMP ping goes out eth0 and comes
> + *   back in eth1.  Reply goes out eth1 and comes back in eth0.  */
> +#include <linux/config.h>
> +#include <linux/netfilter_ipv4.h>
> +#include <linux/ip.h>
> +#include <linux/skbuff.h>
> +#include <linux/moduleparam.h>
> +#include <linux/inetdevice.h>
> +#include <linux/tcp.h>
> +#include <linux/udp.h>
> +#include <linux/icmp.h>
> +#include <linux/version.h>
> +#include <net/ip.h>
> +#include <asm/checksum.h>
> +
> +struct ifinfo
> +{
> +	/* Keep track of name so we can drop reference. */
> +	char name[IFNAMSIZ];
> +
> +	/* Cached interface addr. */
> +	u32 ifaddr;
> +
> +	/* "Phantom" box which gets mapped. */
> +	u32 phantom;
> +};
> +
> +static struct ifinfo devinfo1, devinfo2;
> +
> +/* Stolen from Alexey's ip_nat_dumb. */
> +static int nat_header(struct sk_buff *skb, u32 saddr, u32 daddr)
> +{
> +	struct iphdr *iph = skb->nh.iph;
> +
> +	u32 odaddr = iph->daddr;
> +	u32 osaddr = iph->saddr;
> +	u16 check;
> +
> +	/* Rewrite IP header */
> +	iph->saddr = saddr;
> +	iph->daddr = daddr;
> +	iph->check = 0;
> +	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
> +
> +	/* If it is the first fragment, rewrite protocol headers */
> +	if (!(iph->frag_off & htons(IP_OFFSET))) {
> +		u16 *cksum;
> +
> +		switch(iph->protocol) {
> +		case IPPROTO_TCP:
> +			cksum  = (u16*)&((struct tcphdr*)
> +					 (((char*)iph)+(iph->ihl<<2)))->check;
> +			if ((u8*)(cksum+1) > skb->tail)
> +				return 0;
> +			check = *cksum;
> +			if (skb->ip_summed != CHECKSUM_HW)
> +				check = ~check;
> +			check = csum_tcpudp_magic(iph->saddr, iph->daddr,
> +						  0, 0, check);
> +			check = csum_tcpudp_magic(~osaddr, ~odaddr, 0, 0,
> +						  ~check);
> +			if (skb->ip_summed == CHECKSUM_HW)
> +				check = ~check;
> +			*cksum = check;
> +			break;
> +		case IPPROTO_UDP:
> +			cksum  = (u16*)&((struct udphdr*)
> +					 (((char*)iph)+(iph->ihl<<2)))->check;
> +			if ((u8*)(cksum+1) > skb->tail)
> +				return 0;
> +			if ((check = *cksum) != 0) {
> +				check = csum_tcpudp_magic(iph->saddr, 
> +							  iph->daddr, 0, 0,
> +							  ~check);
> +				check = csum_tcpudp_magic(~osaddr, ~odaddr,
> +							  0, 0, ~check);
> +				*cksum = check ? : 0xFFFF;
> +			}
> +			break;
> +		case IPPROTO_ICMP:
> +		{
> +			struct icmphdr *icmph
> +				= (struct icmphdr*)((char*)iph+(iph->ihl<<2));
> +			struct iphdr *ciph;
> +			u32 idaddr, isaddr;
> +
> +			if ((icmph->type != ICMP_DEST_UNREACH) &&
> +			    (icmph->type != ICMP_TIME_EXCEEDED) &&
> +			    (icmph->type != ICMP_PARAMETERPROB))
> +				break;
> +
> +			ciph = (struct iphdr *) (icmph + 1);
> +
> +			if ((u8*)(ciph+1) > skb->tail)
> +				return 0;
> +
> +			isaddr = ciph->saddr;
> +			idaddr = ciph->daddr;
> +
> +			/* Change addresses inside ICMP packet. */
> +			ciph->daddr = iph->saddr;
> +			ciph->saddr = iph->daddr;
> +			cksum  = &icmph->checksum;
> +			/* Using tcpudp primitive. Why not? */
> +			check  = csum_tcpudp_magic(ciph->saddr, ciph->daddr,
> +						   0, 0, ~(*cksum));
> +			*cksum = csum_tcpudp_magic(~isaddr, ~idaddr, 0, 0,
> +						   ~check);
> +			break;
> +		}
> +		default:
> +			break;
> +		}
> +	}
> +	return 1;
> +}
> +
> +static unsigned int xover_hook(unsigned int hook,
> +			       struct sk_buff **pskb,
> +			       const struct net_device *in,
> +			       const struct net_device *out,
> +			       int (*okfn)(struct sk_buff *))
> +{
> +	/* Going out to phantom box 1: change it to coming from
> +           phantom box 2, and vice versa. */
> +	if ((*pskb)->nh.iph->daddr == devinfo1.phantom) {
> +		printk(KERN_DEBUG "dev1: %u.%u.%u.%u->%u.%u.%u.%u"
> +		       " becomes %u.%u.%u.%u->%u.%u.%u.%u\n",
> +		       NIPQUAD((*pskb)->nh.iph->saddr),
> +		       NIPQUAD((*pskb)->nh.iph->daddr),
> +		       NIPQUAD(devinfo2.phantom),
> +		       NIPQUAD(devinfo2.ifaddr));
> +		if (!nat_header(*pskb, devinfo2.phantom, devinfo2.ifaddr))
> +			return NF_DROP;
> +	} else if ((*pskb)->nh.iph->daddr == devinfo2.phantom) {
> +		printk(KERN_DEBUG "dev1: %u.%u.%u.%u->%u.%u.%u.%u"
> +		       " becomes %u.%u.%u.%u->%u.%u.%u.%u\n",
> +		       NIPQUAD((*pskb)->nh.iph->saddr),
> +		       NIPQUAD((*pskb)->nh.iph->daddr),
> +		       NIPQUAD(devinfo1.phantom),
> +		       NIPQUAD(devinfo1.ifaddr));
> +		if (!nat_header(*pskb, devinfo1.phantom, devinfo1.ifaddr))
> +			return NF_DROP;
> +	}
> +
> +	return NF_ACCEPT;
> +}
> +
> +static struct nf_hook_ops xover_ops
> += { .hook = xover_hook,
> +    .owner = THIS_MODULE,
> +    .pf = PF_INET,
> +    .hooknum = NF_IP_POST_ROUTING, 
> +    .priority = NF_IP_PRI_MANGLE,
> +};
> +
> +static int __set_dev(const char *name, struct ifinfo *ifi)
> +{
> +	struct net_device *dev;
> +	struct in_device *indev;
> +
> +	dev = dev_get_by_name(name);
> +	if (!dev)
> +		goto fail;
> +	indev = __in_dev_get(dev);
> +	if (!indev || !indev->ifa_list)
> +		goto put_fail;
> +
> +	ifi->ifaddr = indev->ifa_list->ifa_address;
> +	ifi->phantom = htonl(ntohl(indev->ifa_list->ifa_address) + 1);
> +	if (ifi->phantom == indev->ifa_list->ifa_broadcast)
> +		goto put_fail;
> +
> +	strlcpy(ifi->name, name, sizeof(ifi->name));
> +	printk(KERN_INFO "ip_crossover: phantom for %s: %u.%u.%u.%u\n",
> +	       ifi->name, NIPQUAD(ifi->phantom));
> +	return 0;
> +
> +put_fail:
> +	dev_put(dev);
> +fail:
> +	printk(KERN_WARNING "ip_crossover: device %s is not usable.\n", name);
> +	return -ENOENT;
> +}
> +
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,50)
> +static int set_dev(const char *val, struct kernel_param *kp)
> +{
> +	return __set_dev(val, kp->arg);
> +}
> +module_param_call(dev1, set_dev, NULL, &devinfo1, 0);
> +module_param_call(dev2, set_dev, NULL, &devinfo2, 0);
> +
> +#define compat_parse_params()
> +#else
> +static char *dev1, *dev2;
> +
> +MODULE_PARM(dev1, "s");
> +MODULE_PARM(dev2, "s");
> +
> +static void compat_parse_params(void)
> +{
> +	if (dev1)
> +		__set_dev(dev1, &devinfo1);
> +	if (dev2)
> +		__set_dev(dev2, &devinfo2);
> +}
> +#endif /* KERNEL_VERSION */
> +
> +static int __init init(void)
> +{
> +	compat_parse_params();
> +
> +	if (!devinfo1.name[0] || !devinfo2.name[0]) {
> +		printk(KERN_ERR "ip_crossover: need dev1 and dev2 args\n");
> +		return -EINVAL;
> +	}
> +
> +	return nf_register_hook(&xover_ops);
> +}
> +
> +static void __exit fini(void)
> +{
> +	struct net_device *dev;
> +
> +	nf_unregister_hook(&xover_ops);
> +
> +	/* Release devices. */
> +	dev = dev_get_by_name(devinfo1.name);
> +	dev_put(dev);
> +	dev_put(dev);
> +
> +	dev = dev_get_by_name(devinfo2.name);
> +	dev_put(dev);
> +	dev_put(dev);
> +}
> +
> +module_init(init);
> +module_exit(fini);
> +MODULE_LICENSE("GPL");
> +MODULE_PARM_DESC(dev1, "First device for crossover (required)");
> +MODULE_PARM_DESC(dev2, "Second device for crossover (required)");
> 
> --
>   Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

-- 
James R. Leu

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

* Re: [PATCH] Netfilter crossover module.
  2003-07-10 14:06 ` James R. Leu
@ 2003-07-10 16:52   ` Ben Greear
  0 siblings, 0 replies; 3+ messages in thread
From: Ben Greear @ 2003-07-10 16:52 UTC (permalink / raw)
  To: jleu; +Cc: Rusty Russell, netdev, netfilter-devel, anton

[-- Attachment #1: Type: text/plain, Size: 1574 bytes --]

James R. Leu wrote:
> Between you and Ben Greear the linux kernel will have every possible
> scheme for sending packets to your self.
> 
> I still think my work on this (Virtual routing and forwarding:
> http://linux-vrf.sf.net/) is the less perverted(*) then the work that either
> you or Ben have come up with.  Plus it has other applications besides
> just being able to send packets to your self.
> 
> * in terms of the concept, not necessarily the actual implementation.

>>It'd be nice to have the module hardwire the arps itself, but this was
>>quickest.  Patch welcome.

It's likely that with my patch you wouldn't have to hard-wire arps at
all.  The primary thing that my patch does is to let a machine answer
arps from a local interface (over the external interface).

Then routing to self can happen by simply(?) binding to the local IP
of your choice and using policy-based routing to route correctly.
(You can loop-back through a router with this patch, for example.)

So, maybe both patches are useful together....

I can't find where I posted my patch last time, so it is
attached again for reference.  It contains a typo-fix in a comment
that may be worthy of inclusion by itself some day :)
Also, when nettool (ethtool) becomes generic, the ioctl code can be
configured through the nettool api, so that new ioctl will go a way.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>       <Ben_Greear AT excite.com>
President of Candela Technologies Inc      http://www.candelatech.com
ScryMUD:  http://scry.wanfear.com     http://scry.wanfear.com/~greear


[-- Attachment #2: sts_2.4.20.patch --]
[-- Type: text/plain, Size: 4420 bytes --]

--- linux-2.4.20/include/linux/sockios.h	2001-11-07 14:39:36.000000000 -0800
+++ linux-2.4.20.c3/include/linux/sockios.h	2003-03-18 14:32:53.000000000 -0800
@@ -65,6 +65,8 @@
 #define SIOCDIFADDR	0x8936		/* delete PA address		*/
 #define	SIOCSIFHWBROADCAST	0x8937	/* set hardware broadcast addr	*/
 #define SIOCGIFCOUNT	0x8938		/* get number of devices */
+#define SIOCGIFWEIGHT	0x8939		/* get weight of device, in stones */
+#define SIOCSIFWEIGHT	0x893a		/* set weight of device, in stones */
 
 #define SIOCGIFBR	0x8940		/* Bridging support		*/
 #define SIOCSIFBR	0x8941		/* Set bridging options 	*/
@@ -92,6 +94,10 @@
 #define SIOCGRARP	0x8961		/* get RARP table entry		*/
 #define SIOCSRARP	0x8962		/* set RARP table entry		*/
 
+/* MAC address based VLAN control calls */
+#define SIOCGIFMACVLAN	0x8965		/* Mac address multiplex/demultiplex support */
+#define SIOCSIFMACVLAN	0x8966		/* Set macvlan options 	*/
+
 /* Driver configuration calls */
 
 #define SIOCGIFMAP	0x8970		/* Get device parameters	*/
@@ -114,6 +120,16 @@
 #define SIOCBONDINFOQUERY      0x8994	/* rtn info about bond state    */
 #define SIOCBONDCHANGEACTIVE   0x8995   /* update to a new active slave */
 			
+
+/* Ben's little hack land */
+#define SIOCSACCEPTLOCALADDRS  0x89a0   /*  Allow interfaces to accept pkts from
+                                         * local interfaces...use with SO_BINDTODEVICE
+                                         */
+#define SIOCGACCEPTLOCALADDRS  0x89a1   /*  Allow interfaces to accept pkts from
+                                         * local interfaces...use with SO_BINDTODEVICE
+                                         */
+
+
 /* Device private ioctl calls */
 
 /*
--- linux-2.4.20/net/Config.in	2002-08-02 17:39:46.000000000 -0700
+++ linux-2.4.20.c3/net/Config.in	2003-03-18 14:32:53.000000000 -0800
@@ -48,6 +48,7 @@
             bool '    Per-VC IP filter kludge' CONFIG_ATM_BR2684_IPFILTER
       fi
    fi
+   tristate 'MAC address based VLANs (EXPERIMENTAL)' CONFIG_MACVLAN
 fi
 tristate '802.1Q VLAN Support' CONFIG_VLAN_8021Q
 
--- linux-2.4.20/net/ipv4/arp.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.20.c3/net/ipv4/arp.c	2003-03-18 14:32:53.000000000 -0800
@@ -1,4 +1,4 @@
-/* linux/net/inet/arp.c
+/* linux/net/inet/arp.c  -*-linux-c-*-
  *
  * Version:	$Id: arp.c,v 1.99 2001/08/30 22:55:42 davem Exp $
  *
@@ -351,12 +351,22 @@
 	int flag = 0; 
 	/*unsigned long now; */
 
-	if (ip_route_output(&rt, sip, tip, 0, 0) < 0) 
+	if (ip_route_output(&rt, sip, tip, 0, 0) < 0)
 		return 1;
-	if (rt->u.dst.dev != dev) { 
-		NET_INC_STATS_BH(ArpFilter);
-		flag = 1;
-	} 
+        
+	if (rt->u.dst.dev != dev) {
+                if ((dev->priv_flags & IFF_ACCEPT_LOCAL_ADDRS) &&
+                    (rt->u.dst.dev == &loopback_dev))  {
+                        /* OK, we'll let this special case slide, so that we can arp from one
+                         * local interface to another.  This seems to work, but could use some
+                         * review. --Ben
+                         */
+                }
+                else {
+                        NET_INC_STATS_BH(ArpFilter);
+                        flag = 1;
+                }
+        }
 	ip_rt_put(rt); 
 	return flag; 
 } 
--- linux-2.4.20/net/ipv4/fib_frontend.c	2002-08-02 17:39:46.000000000 -0700
+++ linux-2.4.20.c3/net/ipv4/fib_frontend.c	2003-03-18 14:32:53.000000000 -0800
@@ -233,8 +233,17 @@
 
 	if (fib_lookup(&key, &res))
 		goto last_resort;
-	if (res.type != RTN_UNICAST)
-		goto e_inval_res;
+        
+	if (res.type != RTN_UNICAST) {
+                if ((res.type == RTN_LOCAL) &&
+                    (dev->priv_flags & IFF_ACCEPT_LOCAL_ADDRS)) {
+                        /* All is OK */
+                }
+                else {
+                        goto e_inval_res;
+                }
+        }
+        
 	*spec_dst = FIB_RES_PREFSRC(res);
 	fib_combine_itag(itag, &res);
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
--- linux-2.4.20/net/ipv4/tcp_ipv4.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.20.c3/net/ipv4/tcp_ipv4.c	2003-03-18 14:32:53.000000000 -0800
@@ -1394,7 +1394,7 @@
 #define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
 #endif
 
-	/* Never answer to SYNs send to broadcast or multicast */
+	/* Never answer to SYNs sent to broadcast or multicast */
 	if (((struct rtable *)skb->dst)->rt_flags & 
 	    (RTCF_BROADCAST|RTCF_MULTICAST))
 		goto drop; 

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

end of thread, other threads:[~2003-07-10 16:52 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-07-10  8:47 [PATCH] Netfilter crossover module Rusty Russell
2003-07-10 14:06 ` James R. Leu
2003-07-10 16:52   ` Ben Greear

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).