diff --git a/src/arp.c b/src/arp.c index 4abd843..b7bddd0 100644 --- a/src/arp.c +++ b/src/arp.c @@ -313,11 +313,11 @@ static int arp_get_gw_hwaddr(struct client_state_t cs[static 1]) if (arp_ping(cs, cs->srcAddr) < 0) return -1; if (cs->routerAddr) { - cs->got_router_arp = false; + cs->router_arp_state = ARP_QUERY; + ++cs->router_arp_sent; if (arp_ping(cs, cs->routerAddr) < 0) return -1; - } else - cs->got_router_arp = true; + } else cs->router_arp_state = ARP_FAILED; garp.wake_ts[AS_GW_QUERY] = garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250; return 0; @@ -465,9 +465,16 @@ int arp_gw_query_timeout(struct client_state_t cs[static 1], long long nowts) garp.wake_ts[AS_GW_QUERY] = rtts; return ARPR_OK; } - if (!cs->got_router_arp) { + if (cs->router_arp_state == ARP_QUERY) { + if (cs->router_arp_sent >= ARP_MAX_TRIES) { + log_line("%s: arp: Gateway is ignoring ARPs.", + client_config.interface); + cs->router_arp_state = ARP_FAILED; + return ARPR_OK; + } log_line("%s: arp: Still looking for gateway hardware address...", client_config.interface); + ++cs->router_arp_sent; if (arp_ping(cs, cs->routerAddr) < 0) { log_warning("%s: arp: Failed to send ARP ping in retransmission.", client_config.interface); @@ -654,7 +661,7 @@ int arp_do_gw_query(struct client_state_t cs[static 1]) client_config.interface, cs->routerArp[0], cs->routerArp[1], cs->routerArp[2], cs->routerArp[3], cs->routerArp[4], cs->routerArp[5]); - cs->got_router_arp = true; + cs->router_arp_state = ARP_FOUND; if (cs->routerAddr == cs->srcAddr) goto server_is_router; if (cs->server_arp_state != ARP_QUERY) { @@ -673,7 +680,7 @@ server_is_router: cs->serverArp[2], cs->serverArp[3], cs->serverArp[4], cs->serverArp[5]); cs->server_arp_state = ARP_FOUND; - if (cs->got_router_arp) { + if (cs->router_arp_state != ARP_QUERY) { garp.wake_ts[AS_GW_QUERY] = -1; if (arp_open_fd(cs, true) < 0) return ARPR_FAIL; diff --git a/src/ndhc.h b/src/ndhc.h index 3040d42..706a222 100644 --- a/src/ndhc.h +++ b/src/ndhc.h @@ -46,15 +46,14 @@ struct client_state_t { long long dhcp_wake_ts; int ifDeconfig; // Set if the interface has already been deconfigured. int epollFd, signalFd, listenFd, arpFd, nlFd, rfkillFd; - int server_arp_sent; + int server_arp_sent, router_arp_sent; uint32_t nlPortId; unsigned int num_dhcp_requests; uint32_t clientAddr, serverAddr, srcAddr, routerAddr; uint32_t lease, xid; uint8_t routerArp[6], serverArp[6]; - enum arp_state server_arp_state; - bool using_dhcp_bpf, got_router_arp, arp_is_defense, - check_fingerprint, program_init; + enum arp_state server_arp_state, router_arp_state; + bool using_dhcp_bpf, arp_is_defense, check_fingerprint, program_init; bool sent_gw_query, sent_first_announce, sent_second_announce, init_fingerprint_inprogress; }; diff --git a/src/state.c b/src/state.c index 0014e74..64d1509 100644 --- a/src/state.c +++ b/src/state.c @@ -78,8 +78,9 @@ static void reinit_shared_deconfig(struct client_state_t cs[static 1]) cs->clientAddr = 0; cs->num_dhcp_requests = 0; cs->server_arp_sent = 0; + cs->router_arp_sent = 0; cs->server_arp_state = ARP_QUERY; - cs->got_router_arp = false; + cs->router_arp_state = ARP_QUERY; cs->check_fingerprint = false; cs->sent_gw_query = false; cs->sent_first_announce = false; @@ -414,7 +415,9 @@ static int frenew(struct client_state_t cs[static 1], bool is_bound) static int ifup_action(struct client_state_t cs[static 1]) { if (cs->routerAddr && cs->serverAddr) { - if ((cs->routerAddr == cs->serverAddr) && cs->server_arp_state != ARP_FOUND) + const bool fp_server = cs->server_arp_state == ARP_FOUND; + const bool fp_router = (cs->routerAddr != cs->serverAddr) ? (cs->router_arp_state == ARP_FOUND) : fp_server; + if (!fp_server && !fp_router) goto no_fingerprint; if (cs->init_fingerprint_inprogress) { suicide("%s: Carrier lost during initial fingerprint. Forcing restart.", @@ -622,7 +625,7 @@ skip_to_requesting: scrReturn(ret); continue; } else BAD_STATE(); - if (!cs->got_router_arp || cs->server_arp_state == ARP_QUERY) { + if (cs->router_arp_state == ARP_QUERY || cs->server_arp_state == ARP_QUERY) { r = arp_do_gw_query(cs); if (r == ARPR_OK) { } else if (r == ARPR_FREE) { @@ -657,7 +660,7 @@ skip_to_requesting: arp_announce_timeout(cs, nowts); if (!cs->sent_gw_query) arp_query_gateway_timeout(cs, nowts); - else if (!cs->got_router_arp || cs->server_arp_state == ARP_QUERY) { + else if (cs->router_arp_state == ARP_QUERY || cs->server_arp_state == ARP_QUERY) { int r = arp_gw_query_timeout(cs, nowts); if (r == ARPR_OK) { } else if (r == ARPR_FAIL) {