Name: CONFIG_IP_NF_CROSSOVER Status: Experimental 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 : the module will be called ip_crossover. diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal linux-2.4.21/Documentation/Configure.help working-2.4.21-crossover/Documentation/Configure.help diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .21559-linux-2.6.6-bk5/net/ipv4/netfilter/Kconfig .21559-linux-2.6.6-bk5.updated/net/ipv4/netfilter/Kconfig --- .21559-linux-2.6.6-bk5/net/ipv4/netfilter/Kconfig 2004-05-10 15:14:04.000000000 +1000 +++ .21559-linux-2.6.6-bk5.updated/net/ipv4/netfilter/Kconfig 2004-05-19 15:19:11.000000000 +1000 @@ -603,5 +603,17 @@ config IP_NF_RAW . If unsure, say `N'. help +config IP_NF_CROSSOVER + tristate "IP forced crossover support" + 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 + : the module will be called + ip_crossover. + endmenu diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .21559-linux-2.6.6-bk5/net/ipv4/netfilter/Makefile .21559-linux-2.6.6-bk5.updated/net/ipv4/netfilter/Makefile --- .21559-linux-2.6.6-bk5/net/ipv4/netfilter/Makefile 2004-05-10 15:14:04.000000000 +1000 +++ .21559-linux-2.6.6-bk5.updated/net/ipv4/netfilter/Makefile 2004-05-19 15:19:46.000000000 +1000 @@ -96,3 +96,4 @@ 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 -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .21559-linux-2.6.6-bk5/net/ipv4/netfilter/ip_crossover.c .21559-linux-2.6.6-bk5.updated/net/ipv4/netfilter/ip_crossover.c --- .21559-linux-2.6.6-bk5/net/ipv4/netfilter/ip_crossover.c 1970-01-01 10:00:00.000000000 +1000 +++ .21559-linux-2.6.6-bk5.updated/net/ipv4/netfilter/ip_crossover.c 2004-05-19 15:43:17.000000000 +1000 @@ -0,0 +1,243 @@ +/* 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 + * arp -s 192.168.2.2 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ifinfo +{ + /* Keep track of name so we can drop reference, and for param. + Must be first element so this can be used as arg to + param_get_charp. + */ + 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 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; + + strncpy(ifi->name, name, sizeof(ifi->name)-1); + 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; +} + +static int set_dev(const char *val, struct kernel_param *kp) +{ + return __set_dev(val, kp->arg); +} + +static struct nf_hook_ops xover_ops += { .hook = xover_hook, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_MANGLE, + .owner = THIS_MODULE, +}; + +static int __init init(void) +{ + 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_param_call(dev1, set_dev, param_get_charp, &devinfo1, 0); +module_param_call(dev2, set_dev, param_get_charp, &devinfo2, 0); +MODULE_LICENSE("GPL"); +MODULE_PARM_DESC(dev1, "First device for crossover (required)"); +MODULE_PARM_DESC(dev2, "Second device for crossover (required)");