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:
		
							
								
								
									
										36
									
								
								ndhc/arp.c
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								ndhc/arp.c
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
			
		||||
/* 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>
 | 
			
		||||
 *
 | 
			
		||||
@@ -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
 | 
			
		||||
                                     // the interface.  Never decreases.
 | 
			
		||||
 | 
			
		||||
static struct dhcpmsg arp_dhcp_packet; // Used only for AS_COLLISION_CHECK
 | 
			
		||||
 | 
			
		||||
static struct arpMsg arpreply;
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
@@ -215,6 +221,7 @@ static int arp_open_fd(struct client_state_t *cs)
 | 
			
		||||
 | 
			
		||||
    cs->arpFd = fd;
 | 
			
		||||
    epoll_add(cs, fd);
 | 
			
		||||
    arpreply_clear();
 | 
			
		||||
    return 0;
 | 
			
		||||
out_fd:
 | 
			
		||||
    close(fd);
 | 
			
		||||
@@ -344,15 +351,10 @@ static int arp_announcement(struct client_state_t *cs)
 | 
			
		||||
}
 | 
			
		||||
#undef BASE_ARPMSG
 | 
			
		||||
 | 
			
		||||
static void arpreply_clear()
 | 
			
		||||
{
 | 
			
		||||
    memset(&arpreply, 0, sizeof arpreply);
 | 
			
		||||
    arpreply_offset = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Callable from DS_SELECTING, DS_RENEWING, or DS_REBINDING via an_packet()
 | 
			
		||||
// Callable from DS_REQUESTING, DS_RENEWING, or DS_REBINDING via an_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);
 | 
			
		||||
    log_line("arp: Probing for hosts that may conflict with our lease...");
 | 
			
		||||
    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;
 | 
			
		||||
    collision_check_init_ts = arp_send_stats[ASEND_COLLISION_CHECK].ts;
 | 
			
		||||
    cs->timeout = probe_wait_time = PROBE_WAIT;
 | 
			
		||||
    memcpy(&arp_dhcp_packet, packet, sizeof (struct dhcpmsg));
 | 
			
		||||
    arpreply_clear();
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -379,8 +379,6 @@ int arp_gw_check(struct client_state_t *cs)
 | 
			
		||||
    cs->dhcpState = DS_BOUND_GW_CHECK;
 | 
			
		||||
    cs->oldTimeout = cs->timeout;
 | 
			
		||||
    cs->timeout = ARP_RETRANS_DELAY + 250;
 | 
			
		||||
    memset(&arp_dhcp_packet, 0, sizeof (struct dhcpmsg));
 | 
			
		||||
    arpreply_clear();
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -394,8 +392,6 @@ static int arp_get_gw_hwaddr(struct client_state_t *cs)
 | 
			
		||||
        return -1;
 | 
			
		||||
    cs->oldTimeout = cs->timeout;
 | 
			
		||||
    cs->timeout = ARP_RETRANS_DELAY + 250;
 | 
			
		||||
    memset(&arp_dhcp_packet, 0, sizeof (struct dhcpmsg));
 | 
			
		||||
    arpreply_clear();
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -627,11 +623,11 @@ void handle_arp_response(struct client_state_t *cs)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // Emulate the BPF filters if they are not in use.
 | 
			
		||||
    if (!using_arp_bpf) {
 | 
			
		||||
        if (!arp_validate_bpf(&arpreply))
 | 
			
		||||
            return;
 | 
			
		||||
        if (arpState == AS_DEFENSE && !arp_validate_bpf_defense(cs, &arpreply))
 | 
			
		||||
            return;
 | 
			
		||||
    if (!using_arp_bpf && (!arp_validate_bpf(&arpreply) ||
 | 
			
		||||
                           (arpState == AS_DEFENSE &&
 | 
			
		||||
                            !arp_validate_bpf_defense(cs, &arpreply)))) {
 | 
			
		||||
        arpreply_clear();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (arpState) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								ndhc/state.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								ndhc/state.c
									
									
									
									
									
								
							@@ -179,14 +179,15 @@ static void bound_gw_check_timeout(struct client_state_t *cs)
 | 
			
		||||
    arp_retransmit(cs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Can transition to DS_BOUND or DS_SELECTING.
 | 
			
		||||
static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet,
 | 
			
		||||
                      uint8_t *message)
 | 
			
		||||
{
 | 
			
		||||
    if (*message == DHCPACK) {
 | 
			
		||||
        uint8_t *temp = NULL;
 | 
			
		||||
        ssize_t optlen;
 | 
			
		||||
        uint8_t *temp = get_option_data(packet, DHCP_LEASE_TIME, &optlen);
 | 
			
		||||
        cs->leaseStartTime = curms();
 | 
			
		||||
        if (!(temp = get_option_data(packet, DHCP_LEASE_TIME, &optlen))) {
 | 
			
		||||
        if (!temp) {
 | 
			
		||||
            log_line("No lease time received, assuming 1h.");
 | 
			
		||||
            cs->lease = 60 * 60;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -203,10 +204,14 @@ static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet,
 | 
			
		||||
        cs->renewTime = cs->lease >> 1;
 | 
			
		||||
        cs->rebindTime = (cs->lease * 0x7) >> 3; // * 0.875
 | 
			
		||||
 | 
			
		||||
        // Can transition from DS_COLLISION_CHECK to DS_BOUND or DS_SELECTING.
 | 
			
		||||
        if (arp_check(cs, packet) == -1) {
 | 
			
		||||
            log_warning("arp_check failed to make arp socket, retrying lease");
 | 
			
		||||
            reinit_selecting(cs, 3000);
 | 
			
		||||
        // 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) {
 | 
			
		||||
                log_warning("arp_check failed to make arp socket, retrying lease");
 | 
			
		||||
                reinit_selecting(cs, 3000);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else if (*message == DHCPNAK) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user