*** linux-2.2.5/net/ipv4/arp.c Sun Mar 21 10:22:00 1999 --- linux/net/ipv4/arp.c Fri Sep 24 17:08:37 1999 *************** *** 65,70 **** --- 65,76 ---- * clean up the APFDDI & gen. FDDI bits. * Alexey Kuznetsov: new arp state machine; * now it is in net/core/neighbour.c. + * Stephen D. Williams: Prevent arp_send() from sending + * responses when the indirect interface + * involved has an inhibit (IFF_NOARP) flag. + * Axel Dunkel : fixes requests from local clients to farm addresses. + * Wensong Zhang : NOARP device (such as tunl) arp fix. + * David Couture : Don't ARP when IIF_LOOPBACK. */ /* RFC1122 Status: *************** *** 427,432 **** --- 438,445 ---- struct sk_buff *skb; struct arphdr *arp; unsigned char *arp_ptr; + struct device *dev_real; /* The real device this ARP is for, if not dev */ + char cbuf[320]; /* * No arp on this interface. *************** *** 436,441 **** --- 449,496 ---- return; /* + * If this ARP is for another device that doesn't want to arp, + * honor that also. (sdw@lig.net) + * All of the next few blocks prevent a number of ARP bugs from + * causing problems, especially in reverse NAT configurations. + * See http://www.LinuxVirtualServer.org for details. + */ + + /* Let's watch ARP's for fun and profit. */ + sprintf(cbuf, "%s arp_send:Re%s src_ip: %s, dest_ip: %s\n", KERN_INFO, + (type==ARPOP_REQUEST)?"quest":"sponse", in_ntoa(src_ip), in_ntoa(dest_ip)); + printk(cbuf); + + dev_real = ip_dev_find(src_ip); + + /* quick fix: warn if down interface is returned */ + if (dev_real != NULL && ( ! (dev_real->flags & IFF_UP))) { + sprintf(cbuf, "%s arp_send: fixme: multiple interfaces with different" + " up/down status but same ip %s detected\n", KERN_INFO, in_ntoa(src_ip)); + printk(cbuf); + dev_real = dev; + } + + if (dev_real != NULL && dev_real != dev) { + char complaint[120]; strcpy(complaint, "arp_send is called with another device's address"); + if (dev_real->flags&IFF_NOARP) { + /* bug fix: arp req for local clients that connect to a farm address 1999-09-17 */ + if (type == ARPOP_REQUEST) { + src_ip = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); + sprintf (cbuf, "%s arp_send: changing source ip to %s\n", KERN_INFO, in_ntoa(src_ip)); + printk(cbuf); + } else { /* Must be a mistaken response. */ + strcpy(complaint, " that doesn't want to arp\n"); + printk(complaint); + return; + } + } else { /* allows ARP, just note */ + strcpy(complaint, "\n"); + printk(complaint); + } + } /* Otherwise device matches IP */ + + /* * Allocate a buffer */ *************** *** 534,539 **** --- 590,596 ---- struct rtable *rt; unsigned char *sha, *tha; u32 sip, tip; + struct device *tdev; u16 dev_type = dev->type; int addr_type; struct in_device *in_dev = dev->ip_ptr; *************** *** 627,632 **** --- 684,699 ---- * addresses. If this is one such, delete it. */ if (LOOPBACK(tip) || MULTICAST(tip)) + goto out; + + /* + * Check for the device flags for the target IP. If the IFF_NOARP + * is set, just delete it. No arp reply is sent. -- WZ + * + * If IFF_LOOPBACK is set, then delete it too. /dc. + */ + if ((tdev = ip_dev_find(tip)) && + ((tdev->flags & IFF_NOARP) || (tdev->flags & IFF_LOOPBACK))) goto out; /*