Support networks with relay agents that have the DHCP server on a
different segment. The network fingerprinting would never complete if the DHCP server was on a different segment before this change, since it would be impossible for the ARP messages sent by ndhc to ever reach the DHCP server (and vice-versa). Now just give up trying to find the hardware address after two tries and assume that the DHCP server cannot be reached by ARP. An alternative would be to fingerprint the relay agent instead, but to do so would require a lot more work as the giaddr field is only meaningful in the client->server message path, not in the server->client path. Thus it would require gathering the source IP for DHCP replies sent by unicast or broadcast and ferrying along this information to the ARP checking code where it would be used in place of the DHCP server address. This is entirely possible to do, but is quite a bit more work.
This commit is contained in:
parent
03fc696267
commit
a395234a67
35
src/arp.c
35
src/arp.c
@ -49,6 +49,10 @@
|
||||
#define ARP_MSG_SIZE 0x2a
|
||||
#define ARP_RETRANS_DELAY 5000 // ms
|
||||
|
||||
// Maximum number of retries when finding the DHCP server ethernet address
|
||||
// via ARP queries before assuming it is on a different segment.
|
||||
#define MAX_DHCP_SERVER_HWADDR_QUERIES 1
|
||||
|
||||
// From RFC5227
|
||||
int arp_probe_wait = 1000; // initial random delay (ms)
|
||||
int arp_probe_num = 3; // number of probe packets
|
||||
@ -568,6 +572,13 @@ static void arp_gw_check_timeout(struct client_state_t *cs, long long nowts)
|
||||
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
|
||||
}
|
||||
|
||||
static void arp_do_gw_query_done(struct client_state_t *cs)
|
||||
{
|
||||
garp.wake_ts[AS_GW_QUERY] = -1;
|
||||
arp_switch_state(cs, AS_DEFENSE);
|
||||
arp_announcement(cs); // Do a second announcement.
|
||||
}
|
||||
|
||||
static void arp_gw_query_timeout(struct client_state_t *cs, long long nowts)
|
||||
{
|
||||
arp_defense_timeout(cs, nowts);
|
||||
@ -584,7 +595,17 @@ static void arp_gw_query_timeout(struct client_state_t *cs, long long nowts)
|
||||
log_warning("%s: arp: Failed to send ARP ping in retransmission.",
|
||||
client_config.interface);
|
||||
}
|
||||
// Here it can be a bit tricky, since DHCP proxies do exist and can
|
||||
// mean that the DHCP server will not be on the local segment and thus
|
||||
// will not respond to ARP. Therefore, the serverAddr can only be
|
||||
// treated as extra information that may or may not exist.
|
||||
if (!cs->got_server_arp) {
|
||||
if (++cs->server_arp_tries > MAX_DHCP_SERVER_HWADDR_QUERIES) {
|
||||
log_line("%s: arp: No ARP response from DHCP server after %d tries. Proceeding.",
|
||||
client_config.interface, cs->server_arp_tries);
|
||||
arp_do_gw_query_done(cs);
|
||||
return;
|
||||
}
|
||||
log_line("%s: arp: Still looking for DHCP server hardware address...",
|
||||
client_config.interface);
|
||||
if (arp_ping(cs, cs->serverAddr) < 0)
|
||||
@ -646,13 +667,6 @@ static void arp_do_defense(struct client_state_t *cs)
|
||||
garp.last_conflict_ts = nowts;
|
||||
}
|
||||
|
||||
static void arp_do_gw_query_done(struct client_state_t *cs)
|
||||
{
|
||||
garp.wake_ts[AS_GW_QUERY] = -1;
|
||||
arp_switch_state(cs, AS_DEFENSE);
|
||||
arp_announcement(cs); // Do a second announcement.
|
||||
}
|
||||
|
||||
static void arp_do_gw_query(struct client_state_t *cs)
|
||||
{
|
||||
if (!arp_is_query_reply(&garp.reply)) {
|
||||
@ -709,6 +723,13 @@ static void arp_do_gw_check(struct client_state_t *cs)
|
||||
// Success only if the router/gw MAC matches stored value
|
||||
if (!memcmp(cs->routerArp, garp.reply.smac, 6)) {
|
||||
garp.router_replied = true;
|
||||
// Handle the case where the DHCP server is proxed from
|
||||
// a different segment and will never reply.
|
||||
if (!cs->got_server_arp &&
|
||||
cs->server_arp_tries > MAX_DHCP_SERVER_HWADDR_QUERIES) {
|
||||
arp_gw_success(cs);
|
||||
return;
|
||||
}
|
||||
if (cs->routerAddr == cs->serverAddr)
|
||||
goto server_is_router;
|
||||
if (garp.server_replied)
|
||||
|
@ -42,6 +42,7 @@ struct client_state_t {
|
||||
int ifDeconfig; // Set if the interface has already been deconfigured.
|
||||
int epollFd, signalFd, listenFd, arpFd, nlFd;
|
||||
int nlPortId;
|
||||
int server_arp_tries;
|
||||
uint32_t clientAddr, serverAddr, routerAddr;
|
||||
uint32_t lease, renewTime, rebindTime, xid;
|
||||
struct nk_random_state_u32 rnd32_state;
|
||||
|
@ -96,6 +96,7 @@ static void reinit_shared_deconfig(struct client_state_t *cs)
|
||||
num_dhcp_requests = 0;
|
||||
cs->got_router_arp = 0;
|
||||
cs->got_server_arp = 0;
|
||||
cs->server_arp_tries = 0;
|
||||
memset(&cs->routerArp, 0, sizeof cs->routerArp);
|
||||
memset(&cs->serverArp, 0, sizeof cs->serverArp);
|
||||
arp_reset_send_stats();
|
||||
|
Loading…
Reference in New Issue
Block a user