
horms at verge
Jun 8, 2004, 2:55 AM
Post #1 of 6
(822 views)
Permalink
|
|
[PATCH] send_arp and RFC2002
|
|
Hi, Sorry this is a bit long. Skip to the Patch Summary below for ths short version. Someone logged a bug against the gratuitous ARP code in fake which I still maintain. http://www.vergenet.net/linux/fake/ This lead me to an investigation of send_arp in both fake and the linux-ha tree. In particular how closely they produce the behaviour in RFC2002 (4.6) which was brought to the attention of linux-ha people in October 2001 by Alan Robertson by way of Masaki Hasegawa. http://www.ietf.org/rfc/rfc2002.txt http://lists.linux-ha.org/pipermail/linux-ha/2001-October/003666.html For reference the RFC states: A Gratuitous ARP [23] is an ARP packet sent by a node in order to spontaneously cause other nodes to update an entry in their ARP cache. A gratuitous ARP MAY use either an ARP Request or an ARP Reply packet. In either case, the ARP Sender Protocol Address and ARP Target Protocol Address are both set to the IP address of the cache entry to be updated, and the ARP Sender Hardware Address is set to the link-layer address to which this cache entry should be updated. When using an ARP Reply packet, the Target Hardware Address is also set to the link-layer address to which this cache entry should be updated (this field is not used in an ARP Request packet). In either case, for a gratuitous ARP, the ARP packet MUST be transmitted as a local broadcast packet on the local link. As specified in [16], any node receiving any ARP packet (Request or Reply) MUST update its local ARP cache with the Sender Protocol and Hardware Addresses in the ARP packet, if the receiving node has an entry for that IP address already in its ARP cache. This requirement in the ARP protocol applies even for ARP Request packets, and for ARP Reply packets that do not match any ARP Request transmitted by the receiving node [16]. Please see the RFC for the references cited in the above quotation. Unfortunately the send arp code in both fake and heartbeat does not follow this in one way or another. I will only discuss the latter as it is relevant to this list. In particular I think there is a problem in the way that the Target Hardware Address (Target MAC Address) is handled in a gratuitous ARP request. The RFC states that this should be "set to the link-layer address to which this cache entry should be updated". The current code set it to ff:ff:ff:ff:ff:ff, the broadcast MAC address. Patch Summary The attached patch resolves this problem and makes two other changes. The details of changes the patch makes are: 1. Target Hardware Address (In the ARP portion of the packet) a) ARP Reply Set to the MAC address we want associated with the VIP. The Source Hardware Address is already set to this value Previously set to ff:ff:ff:ff:ff:ff b) ARP Request Set to 00:00:00:00:00:00. According to the RFC quotation above, this value is not used in an arp Request, so the value should not matter. However from observation of packets on the local network at VAJ, I observed that typically (always?) this value is set to 00:00:00:00:00:00. It seems harmless enough to follow this trend. Previously set to ff:ff:ff:ff:ff:ff 2. Source Hardware Address (Ethernet Header, not in the ARP portion of the packet) Set to the MAC address of the interface that the packet is being sent to. Actually, due to the way that send_arp is called this would usually (always?) be the case anyway. Although this value should not really matter, it seems sensible to set the source address to where the packet is really coming from. The other obvious choice would be the MAC address that is being associated for the VIP. Which was the previous values. Again, these are typically the same thing. Previously set to MAC address being associated with the VIP Alan, others, are there any objections to these changes. -- Horms -------------- next part -------------- Index: send_arp.c =================================================================== RCS file: /home/cvs/linux-ha/linux-ha/heartbeat/libnet_util/send_arp.c,v retrieving revision 1.11 diff -u -r1.11 send_arp.c --- send_arp.c 27 Apr 2004 11:55:54 -0000 1.11 +++ send_arp.c 8 Jun 2004 08:27:44 -0000 @@ -309,7 +309,10 @@ { int n; u_char *buf; - u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u_char *target_mac; + u_char device_mac[6]; + u_char bcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u_char zero_mac[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if (libnet_init_packet(LIBNET_ARP_H + LIBNET_ETH_H, &buf) == -1) { @@ -320,13 +323,30 @@ /* Convert ASCII Mac Address to 6 Hex Digits. */ /* Ethernet header */ - if (libnet_build_ethernet(enet_dst, macaddr, ETHERTYPE_ARP, NULL, 0 + if (get_hw_addr(device, device_mac) < 0) { + syslog(LOG_ERR, "Cannot find mac address for %s", + device); + return -1; + } + + if (libnet_build_ethernet(bcast_mac, device_mac, ETHERTYPE_ARP, NULL, 0 , buf) == -1) { syslog(LOG_ERR, "libnet_build_ethernet failed:"); libnet_destroy_packet(&buf); return -1; } + if (arptype == ARPOP_REQUEST) { + target_mac = zero_mac; + } + else if (arptype == ARPOP_REPLY) { + target_mac = macaddr; + } + else { + syslog(LOG_ERR, "unkonwn arptype:"); + return -1; + } + /* * ARP header */ @@ -337,7 +357,7 @@ arptype, /* ARP operation */ macaddr, /* Source hardware addr */ (u_char *)&ip, /* Target hardware addr */ - enet_dst, /* Destination hw addr */ + target_mac, /* Destination hw addr */ (u_char *)&ip, /* Target protocol address */ NULL, /* Payload */ 0, /* Payload length */ @@ -365,7 +385,21 @@ send_arp(libnet_t* lntag, u_long ip, u_char *device, u_char macaddr[6], u_char *broadcast, u_char *netmask, u_short arptype) { int n; - u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u_char *target_mac; + u_char device_mac[6]; + u_char bcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u_char zero_mac[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + if (arptype == ARPOP_REQUEST) { + target_mac = zero_mac; + } + else if (arptype == ARPOP_REPLY) { + target_mac = macaddr; + } + else { + syslog(LOG_ERR, "unkonwn arptype:"); + return -1; + } /* * ARP header @@ -377,7 +411,7 @@ arptype, /* ARP operation type */ macaddr, /* sender Hardware address */ (u_char *)&ip, /* sender protocol address */ - enet_dst, /* target hardware address */ + target_mac, /* target hardware address */ (u_char *)&ip, /* target protocol address */ NULL, /* Payload */ 0, /* Length of payload */ @@ -389,7 +423,13 @@ } /* Ethernet header */ - if (libnet_build_ethernet(enet_dst, macaddr, ETHERTYPE_ARP, NULL, 0 + if (get_hw_addr(device, device_mac) < 0) { + syslog(LOG_ERR, "Cannot find mac address for %s", + device); + return -1; + } + + if (libnet_build_ethernet(bcast_mac, device_mac, ETHERTYPE_ARP, NULL, 0 , lntag, 0) == -1 ) { syslog(LOG_ERR, "libnet_build_ethernet failed:"); return -1;
|