From: Roy Marples Date: Thu, 29 May 2008 11:58:25 +0000 (+0000) Subject: Respect RFC 3927 more, regarding times and conflicts. X-Git-Tag: v4.0.2~310 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3cf0d215a5c211d8e1b7a1b6a4c982e62b4de682;p=thirdparty%2Fdhcpcd.git Respect RFC 3927 more, regarding times and conflicts. --- diff --git a/net.c b/net.c index f0e26e3d..762de76e 100644 --- a/net.c +++ b/net.c @@ -591,12 +591,6 @@ valid_udp_packet(const uint8_t *data) } #ifdef ENABLE_ARP -/* These are really for IPV4LL */ -#define NPROBES 3 -#define PROBE_INTERVAL 200 -#define NCLAIMS 2 -#define CLAIM_INTERVAL 200 - static int send_arp(const struct interface *iface, int op, struct in_addr sip, const unsigned char *taddr, struct in_addr tip) @@ -640,9 +634,12 @@ arp_claim(struct interface *iface, struct in_addr address) { struct arphdr reply; uint8_t arp_reply[sizeof(reply) + 2 * 4 /* IPv4 */ + 2 * 8 /* EUI64 */]; - struct in_addr reply_ipv4; - struct ether_addr reply_mac; - long timeout = 0; + uint8_t *p; + struct ether_addr reply_smac; + struct in_addr reply_sipv4; + struct ether_addr reply_tmac; + struct in_addr reply_tipv4; + long timeout; int retval = -1; int nprobes = 0; int nclaims = 0; @@ -667,7 +664,12 @@ arp_claim(struct interface *iface, struct in_addr address) "checking %s is available on attached networks", inet_ntoa(address)); - if (!open_socket(iface, ETHERTYPE_ARP)) { + timeout = arc4random() % PROBE_WAIT; + if (get_time(&stopat) != 0) + return -1; + stopat.tv_usec += timeout * 1000; + + if (open_socket(iface, ETHERTYPE_ARP) == -1) { logger (LOG_ERR, "open_socket: %s", strerror(errno)); return -1; } @@ -681,19 +683,28 @@ arp_claim(struct interface *iface, struct in_addr address) /* Only poll if we have a timeout */ if (timeout > 0) { + /* Obey IPV4LL timings, but make us faster for + * routeable addresses */ + if (IN_LINKLOCAL(htonl(address.s_addr))) + timeout *= 1000; + else + timeout *= 200; s = poll(fds, 2, timeout); if (s == -1) { if (errno != EINTR) - logger(LOG_ERR, "poll: `%s'", strerror(errno)); + logger(LOG_ERR, "poll: `%s'", + strerror(errno)); break; } } /* Timed out */ if (s == 0) { - if (nprobes < NPROBES) { - nprobes ++; - timeout = PROBE_INTERVAL; + if (nprobes < PROBE_NUM) { + nprobes++; + timeout = (arc4random() % + (PROBE_MAX - PROBE_MIN)) + + PROBE_MIN; logger(LOG_DEBUG, "sending ARP probe #%d", nprobes); if (send_arp(iface, ARPOP_REQUEST, @@ -703,12 +714,12 @@ arp_claim(struct interface *iface, struct in_addr address) /* IEEE1394 cannot set ARP target address * according to RFC2734 */ - if (nprobes >= NPROBES && + if (nprobes >= PROBE_NUM && iface->family == ARPHRD_IEEE1394) - nclaims = NCLAIMS; - } else if (nclaims < NCLAIMS) { - nclaims ++; - timeout = CLAIM_INTERVAL; + nclaims = ANNOUNCE_NUM; + } else if (nclaims < ANNOUNCE_NUM) { + nclaims++; + timeout = ANNOUNCE_INTERVAL; logger(LOG_DEBUG, "sending ARP claim #%d", nclaims); if (send_arp(iface, ARPOP_REQUEST, @@ -724,7 +735,7 @@ arp_claim(struct interface *iface, struct in_addr address) /* Setup our stop time */ if (get_time(&stopat) != 0) break; - stopat.tv_usec += timeout; + stopat.tv_usec += timeout * 1000; continue; } @@ -752,43 +763,46 @@ arp_claim(struct interface *iface, struct in_addr address) break; memcpy(&reply, arp_reply, sizeof(reply)); - /* Only these types are recognised */ - if (reply.ar_op != htons(ARPOP_REPLY)) - continue; /* Protocol must be IP. */ if (reply.ar_pro != htons(ETHERTYPE_IP)) continue; - if (reply.ar_pln != sizeof(reply_ipv4)) + if (reply.ar_pln != sizeof(reply_sipv4)) continue; if ((size_t)bytes < sizeof(reply) + 2 * (4 + reply.ar_hln) || reply.ar_hln > 8) continue; - memcpy(&reply_mac, - arp_reply + sizeof(reply), reply.ar_hln); - memcpy(&reply_ipv4, - arp_reply + sizeof(reply) + reply.ar_hln, - reply.ar_pln); - - /* Ensure the ARP reply is for the our address */ - if (reply_ipv4.s_addr != address.s_addr) - continue; - - /* Some systems send a reply back from our hwaddress, - * which is wierd */ - if (reply.ar_hln == iface->hwlen && - memcmp(&reply_mac, iface->hwaddr, - iface->hwlen) == 0) + /* Only these types are recognised */ + if (reply.ar_op != htons(ARPOP_REPLY) && + reply.ar_op != htons(ARPOP_REQUEST)) continue; - logger(LOG_ERR, "ARPOP_REPLY received from %s (%s)", - inet_ntoa(reply_ipv4), - hwaddr_ntoa((unsigned char *)&reply_mac, - (size_t)reply.ar_hln)); - errno = EEXIST; - retval = -1; - goto eexit; + /* Copy out the ARP packet */ + p = arp_reply + sizeof(reply); + memcpy(&reply_smac, p, reply.ar_hln); + p += reply.ar_hln; + memcpy(&reply_sipv4, p, reply.ar_pln); + p += reply.ar_pln; + memcpy(&reply_tmac, p, reply.ar_hln); + p += reply.ar_hln; + memcpy(&reply_tipv4, p, reply.ar_pln); + + /* Check for conflict */ + if (reply_sipv4.s_addr == address.s_addr || + (reply_tipv4.s_addr == address.s_addr && + reply.ar_op == htons(ARPOP_REQUEST) && + memcmp(&reply_smac, iface->hwaddr, + iface->hwlen) != 0)) + { + logger(LOG_ERR, "hardware address %s claims %s", + hwaddr_ntoa((unsigned char *)&reply_smac, + (size_t)reply.ar_hln), + inet_ntoa(address)); + errno = EEXIST; + retval = -1; + goto eexit; + } } } diff --git a/net.h b/net.h index d821fdbd..77e4b6f9 100644 --- a/net.h +++ b/net.h @@ -171,6 +171,17 @@ ssize_t send_raw_packet(const struct interface *, int, ssize_t get_packet(struct interface *, void *, ssize_t); #ifdef ENABLE_ARP +/* These are really for IPV4LL */ +#define PROBE_WAIT 1 +#define PROBE_NUM 3 +#define PROBE_MIN 1 +#define PROBE_MAX 2 +#define ANNOUNCE_WAIT 2 +#define ANNOUNCE_NUM 2 +#define ANNOUNCE_INTERVAL 2 +#define MAX_CONFLICTS 10 +#define RATE_LIMIT_INTERVAL 60 +#define DEFEND_INTERVAL 10 int arp_claim(struct interface *, struct in_addr); #endif #endif