Only perform arpreply_clear() after consuming an arp packet in

handle_arp_response() and when opening a new arp fd.  Do not clear the
arpreply buffer and offset on ARP state transitions.

Only perform ARP collision probing when binding a new lease from the
DS_REQUESTING state, or if we have renewed or rebound a lease with a different
IP than we had before.

Resequence the arp_dhcp_packet memcpy() in arp_check() so that the current
IP address is ARP checked rather than the previous one.
This commit is contained in:
Nicholas J. Kain 2011-07-06 09:26:07 -04:00
parent a92cb1c4c6
commit ad5c5d6803
2 changed files with 27 additions and 26 deletions

View File

@ -1,5 +1,5 @@
/* arp.c - arp ping checking /* arp.c - arp ping checking
* Time-stamp: <2011-07-06 08:41:06 njk> * Time-stamp: <2011-07-06 09:18:58 njk>
* *
* Copyright 2010-2011 Nicholas J. Kain <njkain@gmail.com> * Copyright 2010-2011 Nicholas J. Kain <njkain@gmail.com>
* *
@ -95,9 +95,15 @@ static uint16_t probe_wait_time; // Time to wait for a COLLISION_CHECK reply.
static unsigned int total_conflicts; // Total number of address conflicts on static unsigned int total_conflicts; // Total number of address conflicts on
// the interface. Never decreases. // the interface. Never decreases.
static struct dhcpmsg arp_dhcp_packet; // Used only for AS_COLLISION_CHECK
static struct arpMsg arpreply; static struct arpMsg arpreply;
static int arpreply_offset; static int arpreply_offset;
static struct dhcpmsg arp_dhcp_packet; // Used only for AS_COLLISION_CHECK static void arpreply_clear(void)
{
memset(&arpreply, 0, sizeof arpreply);
arpreply_offset = 0;
}
void arp_reset_send_stats(void) void arp_reset_send_stats(void)
{ {
@ -215,6 +221,7 @@ static int arp_open_fd(struct client_state_t *cs)
cs->arpFd = fd; cs->arpFd = fd;
epoll_add(cs, fd); epoll_add(cs, fd);
arpreply_clear();
return 0; return 0;
out_fd: out_fd:
close(fd); close(fd);
@ -344,15 +351,10 @@ static int arp_announcement(struct client_state_t *cs)
} }
#undef BASE_ARPMSG #undef BASE_ARPMSG
static void arpreply_clear() // Callable from DS_REQUESTING, DS_RENEWING, or DS_REBINDING via an_packet()
{
memset(&arpreply, 0, sizeof arpreply);
arpreply_offset = 0;
}
// Callable from DS_SELECTING, DS_RENEWING, or DS_REBINDING via an_packet()
int arp_check(struct client_state_t *cs, struct dhcpmsg *packet) int arp_check(struct client_state_t *cs, struct dhcpmsg *packet)
{ {
memcpy(&arp_dhcp_packet, packet, sizeof (struct dhcpmsg));
arp_switch_state(cs, AS_COLLISION_CHECK); arp_switch_state(cs, AS_COLLISION_CHECK);
log_line("arp: Probing for hosts that may conflict with our lease..."); log_line("arp: Probing for hosts that may conflict with our lease...");
if (arp_ip_anon_ping(cs, arp_dhcp_packet.yiaddr) == -1) if (arp_ip_anon_ping(cs, arp_dhcp_packet.yiaddr) == -1)
@ -361,8 +363,6 @@ int arp_check(struct client_state_t *cs, struct dhcpmsg *packet)
cs->dhcpState = DS_COLLISION_CHECK; cs->dhcpState = DS_COLLISION_CHECK;
collision_check_init_ts = arp_send_stats[ASEND_COLLISION_CHECK].ts; collision_check_init_ts = arp_send_stats[ASEND_COLLISION_CHECK].ts;
cs->timeout = probe_wait_time = PROBE_WAIT; cs->timeout = probe_wait_time = PROBE_WAIT;
memcpy(&arp_dhcp_packet, packet, sizeof (struct dhcpmsg));
arpreply_clear();
return 0; return 0;
} }
@ -379,8 +379,6 @@ int arp_gw_check(struct client_state_t *cs)
cs->dhcpState = DS_BOUND_GW_CHECK; cs->dhcpState = DS_BOUND_GW_CHECK;
cs->oldTimeout = cs->timeout; cs->oldTimeout = cs->timeout;
cs->timeout = ARP_RETRANS_DELAY + 250; cs->timeout = ARP_RETRANS_DELAY + 250;
memset(&arp_dhcp_packet, 0, sizeof (struct dhcpmsg));
arpreply_clear();
return 0; return 0;
} }
@ -394,8 +392,6 @@ static int arp_get_gw_hwaddr(struct client_state_t *cs)
return -1; return -1;
cs->oldTimeout = cs->timeout; cs->oldTimeout = cs->timeout;
cs->timeout = ARP_RETRANS_DELAY + 250; cs->timeout = ARP_RETRANS_DELAY + 250;
memset(&arp_dhcp_packet, 0, sizeof (struct dhcpmsg));
arpreply_clear();
return 0; return 0;
} }
@ -627,10 +623,10 @@ void handle_arp_response(struct client_state_t *cs)
return; return;
// Emulate the BPF filters if they are not in use. // Emulate the BPF filters if they are not in use.
if (!using_arp_bpf) { if (!using_arp_bpf && (!arp_validate_bpf(&arpreply) ||
if (!arp_validate_bpf(&arpreply)) (arpState == AS_DEFENSE &&
return; !arp_validate_bpf_defense(cs, &arpreply)))) {
if (arpState == AS_DEFENSE && !arp_validate_bpf_defense(cs, &arpreply)) arpreply_clear();
return; return;
} }

View File

@ -179,14 +179,15 @@ static void bound_gw_check_timeout(struct client_state_t *cs)
arp_retransmit(cs); arp_retransmit(cs);
} }
// Can transition to DS_BOUND or DS_SELECTING.
static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet, static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet,
uint8_t *message) uint8_t *message)
{ {
if (*message == DHCPACK) { if (*message == DHCPACK) {
uint8_t *temp = NULL;
ssize_t optlen; ssize_t optlen;
uint8_t *temp = get_option_data(packet, DHCP_LEASE_TIME, &optlen);
cs->leaseStartTime = curms(); cs->leaseStartTime = curms();
if (!(temp = get_option_data(packet, DHCP_LEASE_TIME, &optlen))) { if (!temp) {
log_line("No lease time received, assuming 1h."); log_line("No lease time received, assuming 1h.");
cs->lease = 60 * 60; cs->lease = 60 * 60;
} else { } else {
@ -203,11 +204,15 @@ static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet,
cs->renewTime = cs->lease >> 1; cs->renewTime = cs->lease >> 1;
cs->rebindTime = (cs->lease * 0x7) >> 3; // * 0.875 cs->rebindTime = (cs->lease * 0x7) >> 3; // * 0.875
// Can transition from DS_COLLISION_CHECK to DS_BOUND or DS_SELECTING. // Only check if we are either in the REQUESTING state, or if we
// have received a lease with a different IP than what we had before.
if (cs->dhcpState == DS_REQUESTING ||
memcmp(&packet->yiaddr, &cs->clientAddr, 4)) {
if (arp_check(cs, packet) == -1) { if (arp_check(cs, packet) == -1) {
log_warning("arp_check failed to make arp socket, retrying lease"); log_warning("arp_check failed to make arp socket, retrying lease");
reinit_selecting(cs, 3000); reinit_selecting(cs, 3000);
} }
}
} else if (*message == DHCPNAK) { } else if (*message == DHCPNAK) {
log_line("Received DHCP NAK."); log_line("Received DHCP NAK.");