From 7bd551d5644fab1d7866094a35ef6babe39e9212 Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Mon, 19 Oct 2020 03:07:23 -0400 Subject: [PATCH] Give up on fingerprinting relay agent/server if it doesn't reply. Try to send/wait three times; then if there's no response, then assume that the relay agent is ignoring or firewalled from receiving ARP requests. --- src/arp.c | 17 +++++++++++++---- src/ndhc.h | 10 +++++++++- src/state.c | 10 +++++++--- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/arp.c b/src/arp.c index 1faa029..4abd843 100644 --- a/src/arp.c +++ b/src/arp.c @@ -49,6 +49,7 @@ #define ARP_MSG_SIZE 0x2a #define ARP_RETRANS_DELAY 5000 // ms +#define ARP_MAX_TRIES 3 // From RFC5227 int arp_probe_wait = 1000; // initial random delay (ms) @@ -307,7 +308,8 @@ static int arp_get_gw_hwaddr(struct client_state_t cs[static 1]) else log_line("%s: arp: Searching for dhcp server address...", client_config.interface); - cs->got_server_arp = false; + cs->server_arp_state = ARP_QUERY; + ++cs->server_arp_sent; if (arp_ping(cs, cs->srcAddr) < 0) return -1; if (cs->routerAddr) { @@ -472,9 +474,16 @@ int arp_gw_query_timeout(struct client_state_t cs[static 1], long long nowts) return ARPR_FAIL; } } - if (!cs->got_server_arp) { + if (cs->server_arp_state == ARP_QUERY) { + if (cs->server_arp_sent >= ARP_MAX_TRIES) { + log_line("%s: arp: DHCP agent is ignoring ARPs.", + client_config.interface); + cs->server_arp_state = ARP_FAILED; + return ARPR_OK; + } log_line("%s: arp: Still looking for DHCP agent hardware address...", client_config.interface); + ++cs->server_arp_sent; if (arp_ping(cs, cs->srcAddr) < 0) { log_warning("%s: arp: Failed to send ARP ping in retransmission.", client_config.interface); @@ -648,7 +657,7 @@ int arp_do_gw_query(struct client_state_t cs[static 1]) cs->got_router_arp = true; if (cs->routerAddr == cs->srcAddr) goto server_is_router; - if (cs->got_server_arp) { + if (cs->server_arp_state != ARP_QUERY) { garp.wake_ts[AS_GW_QUERY] = -1; if (arp_open_fd(cs, true) < 0) return ARPR_FAIL; @@ -663,7 +672,7 @@ server_is_router: client_config.interface, cs->serverArp[0], cs->serverArp[1], cs->serverArp[2], cs->serverArp[3], cs->serverArp[4], cs->serverArp[5]); - cs->got_server_arp = true; + cs->server_arp_state = ARP_FOUND; if (cs->got_router_arp) { garp.wake_ts[AS_GW_QUERY] = -1; if (arp_open_fd(cs, true) < 0) diff --git a/src/ndhc.h b/src/ndhc.h index f3b2079..3040d42 100644 --- a/src/ndhc.h +++ b/src/ndhc.h @@ -34,18 +34,26 @@ #include #include "nk/random.h" +enum arp_state { + ARP_QUERY = 0, + ARP_FOUND, + ARP_FAILED, +}; + struct client_state_t { struct nk_random_state rnd_state; long long leaseStartTime, renewTime, rebindTime; 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; uint32_t nlPortId; unsigned int num_dhcp_requests; uint32_t clientAddr, serverAddr, srcAddr, routerAddr; uint32_t lease, xid; uint8_t routerArp[6], serverArp[6]; - bool using_dhcp_bpf, got_router_arp, got_server_arp, arp_is_defense, + enum arp_state server_arp_state; + bool using_dhcp_bpf, got_router_arp, 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 e3d8f9f..66d7811 100644 --- a/src/state.c +++ b/src/state.c @@ -77,8 +77,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->server_arp_state = ARP_QUERY; cs->got_router_arp = false; - cs->got_server_arp = false; cs->check_fingerprint = false; cs->sent_gw_query = false; cs->sent_first_announce = false; @@ -417,6 +418,8 @@ 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) + goto no_fingerprint; if (cs->init_fingerprint_inprogress) { suicide("%s: Carrier lost during initial fingerprint. Forcing restart.", client_config.interface); @@ -431,6 +434,7 @@ static int ifup_action(struct client_state_t cs[static 1]) return IFUP_FAIL; } } +no_fingerprint: log_line("%s: Interface is back. Searching for new lease...", client_config.interface); return IFUP_NEWLEASE; @@ -622,7 +626,7 @@ skip_to_requesting: scrReturn(ret); continue; } else BAD_STATE(); - if (!cs->got_router_arp || !cs->got_server_arp) { + if (!cs->got_router_arp || cs->server_arp_state == ARP_QUERY) { r = arp_do_gw_query(cs); if (r == ARPR_OK) { } else if (r == ARPR_FREE) { @@ -657,7 +661,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->got_server_arp) { + else if (!cs->got_router_arp || cs->server_arp_state == ARP_QUERY) { int r = arp_gw_query_timeout(cs, nowts); if (r == ARPR_OK) { } else if (r == ARPR_FAIL) {