arp: Handle initial announcement asynchronously and retry failures.
We need to send two ARP announcements, so these are now done via a timeout callback so that failures can be handled properly.
This commit is contained in:
parent
4d87d5075a
commit
34a8cd7ad9
30
src/arp.c
30
src/arp.c
@ -63,7 +63,7 @@ int arp_probe_max = 2000; // maximum delay until repeated probe (ms)
|
||||
#define DEFEND_INTERVAL 10000 // minimum interval between defensive ARPs
|
||||
|
||||
static struct arp_data garp = {
|
||||
.wake_ts = { -1, -1, -1, -1, -1 },
|
||||
.wake_ts = { -1, -1, -1, -1, -1, -1 },
|
||||
.send_stats = {{0,0},{0,0},{0,0}},
|
||||
.last_conflict_ts = 0,
|
||||
.gw_check_initpings = 0,
|
||||
@ -565,14 +565,36 @@ int arp_query_gateway(struct client_state_t cs[static 1])
|
||||
|
||||
int arp_announce(struct client_state_t cs[static 1])
|
||||
{
|
||||
if (cs->sent_first_announce && cs->sent_second_announce) {
|
||||
garp.wake_ts[AS_ANNOUNCE] = -1;
|
||||
return ARPR_OK;
|
||||
}
|
||||
if (arp_announcement(cs) < 0) {
|
||||
log_warning("%s: (%s) Failed to send ARP announcement: %s",
|
||||
client_config.interface, __func__, strerror(errno));
|
||||
garp.wake_ts[AS_ANNOUNCE] = curms() + ARP_RETRANS_DELAY ;
|
||||
return ARPR_FAIL;
|
||||
}
|
||||
if (!cs->sent_first_announce)
|
||||
cs->sent_first_announce = true;
|
||||
else if (!cs->sent_second_announce)
|
||||
cs->sent_second_announce = true;
|
||||
if (!cs->sent_first_announce || !cs->sent_second_announce)
|
||||
garp.wake_ts[AS_ANNOUNCE] = curms() + ARP_RETRANS_DELAY;
|
||||
else
|
||||
garp.wake_ts[AS_ANNOUNCE] = -1;
|
||||
return ARPR_OK;
|
||||
}
|
||||
|
||||
// 1 == not yet time, 0 == timed out, success, -1 == timed out, failure
|
||||
int arp_announce_timeout(struct client_state_t cs[static 1], long long nowts)
|
||||
{
|
||||
long long rtts = garp.wake_ts[AS_ANNOUNCE];
|
||||
if (rtts == -1) return 0;
|
||||
if (nowts < rtts) return 1;
|
||||
return arp_announce(cs) == ARPR_OK ? 0 : -1;
|
||||
}
|
||||
|
||||
int arp_do_defense(struct client_state_t cs[static 1])
|
||||
{
|
||||
// Even though the BPF will usually catch this case, sometimes there are
|
||||
@ -620,9 +642,6 @@ int arp_do_gw_query(struct client_state_t cs[static 1])
|
||||
garp.wake_ts[AS_GW_QUERY] = -1;
|
||||
if (arp_open_fd(cs, true) < 0)
|
||||
return ARPR_FAIL;
|
||||
// Do a second announcement.
|
||||
if (arp_announcement(cs) < 0)
|
||||
return ARPR_FAIL;
|
||||
return ARPR_FREE;
|
||||
}
|
||||
return ARPR_OK;
|
||||
@ -639,9 +658,6 @@ server_is_router:
|
||||
garp.wake_ts[AS_GW_QUERY] = -1;
|
||||
if (arp_open_fd(cs, true) < 0)
|
||||
return ARPR_FAIL;
|
||||
// Do a second announcement.
|
||||
if (arp_announcement(cs) < 0)
|
||||
return ARPR_FAIL;
|
||||
return ARPR_FREE;
|
||||
}
|
||||
return ARPR_OK;
|
||||
|
@ -60,6 +60,7 @@ extern int arp_probe_max;
|
||||
|
||||
typedef enum {
|
||||
AS_NONE = 0, // Nothing to react to wrt ARP
|
||||
AS_ANNOUNCE, // Announcing our MAC/IP mapping to ethernet peers.
|
||||
AS_COLLISION_CHECK, // Checking to see if another host has our IP before
|
||||
// accepting a new lease.
|
||||
AS_GW_CHECK, // Seeing if the default GW still exists on the local
|
||||
@ -119,7 +120,9 @@ int arp_do_collision_check(struct client_state_t cs[static 1]);
|
||||
int arp_collision_timeout(struct client_state_t cs[static 1], long long nowts);
|
||||
|
||||
int arp_query_gateway(struct client_state_t cs[static 1]);
|
||||
|
||||
int arp_announce(struct client_state_t cs[static 1]);
|
||||
int arp_announce_timeout(struct client_state_t cs[static 1], long long nowts);
|
||||
|
||||
int arp_do_defense(struct client_state_t cs[static 1]);
|
||||
int arp_defense_timeout(struct client_state_t cs[static 1], long long nowts);
|
||||
|
@ -47,6 +47,7 @@ struct client_state_t {
|
||||
uint8_t routerArp[6], serverArp[6];
|
||||
bool using_dhcp_bpf, got_router_arp, got_server_arp, arp_is_defense,
|
||||
check_fingerprint, program_init;
|
||||
bool sent_gw_query, sent_first_announce, sent_second_announce;
|
||||
};
|
||||
|
||||
struct client_config_t {
|
||||
|
@ -537,8 +537,9 @@ skip_to_requesting:
|
||||
if (arp_timeout) {
|
||||
int r = arp_collision_timeout(cs, nowts);
|
||||
if (r == ARPR_FREE) {
|
||||
arp_query_gateway(cs); // XXX: Handle failure
|
||||
arp_announce(cs); // XXX: Handle failure
|
||||
if (arp_query_gateway(cs) == ARPR_OK)
|
||||
cs->sent_gw_query = true; // XXX: Handle the false case
|
||||
arp_announce(cs);
|
||||
break;
|
||||
} else if (r == ARPR_OK) {
|
||||
} else if (r == ARPR_FAIL) {
|
||||
@ -643,6 +644,8 @@ skip_to_requesting:
|
||||
}
|
||||
if (arp_timeout) {
|
||||
arp_defense_timeout(cs, nowts);
|
||||
if (!cs->sent_first_announce || !cs->sent_second_announce)
|
||||
arp_announce_timeout(cs, nowts);
|
||||
if (!cs->got_router_arp || !cs->got_server_arp) {
|
||||
int r = arp_gw_query_timeout(cs, nowts);
|
||||
if (r == ARPR_OK) {
|
||||
|
Loading…
Reference in New Issue
Block a user