Consolidate all of the global static variables in arp.c into a single

struct, and use booleans where appropriate.
This commit is contained in:
Nicholas J. Kain 2014-04-06 22:12:31 -04:00
parent a86363f248
commit e2ee728982
3 changed files with 160 additions and 144 deletions

300
src/arp.c
View File

@ -61,7 +61,6 @@ int arp_probe_max = 2000; // maximum delay until repeated probe (ms)
#define RATE_LIMIT_INTERVAL 60000 // delay between successive attempts
#define DEFEND_INTERVAL 10000 // minimum interval between defensive ARPs
typedef enum {
AS_NONE = 0, // Nothing to react to wrt ARP
AS_COLLISION_CHECK, // Checking to see if another host has our IP before
@ -73,8 +72,6 @@ typedef enum {
AS_MAX,
} arp_state_t;
static long long arp_wake_ts[AS_MAX] = { -1, -1, -1, -1, -1 };
typedef enum {
ASEND_COLLISION_CHECK,
ASEND_GW_PING,
@ -82,45 +79,62 @@ typedef enum {
ASEND_MAX,
} arp_send_t;
static arp_state_t arpState;
struct arp_stats {
long long ts;
int count;
};
static struct arp_stats arp_send_stats[ASEND_MAX];
static int using_arp_bpf; // Is a BPF installed on the ARP socket?
int arp_relentless_def; // Don't give up defense no matter what.
static long long last_conflict_ts; // TS of the last conflicting ARP seen.
struct arp_data {
struct dhcpmsg dhcp_packet; // Used only for AS_COLLISION_CHECK
struct arpMsg reply;
struct arp_stats send_stats[ASEND_MAX];
long long wake_ts[AS_MAX];
long long last_conflict_ts; // TS of the last conflicting ARP seen.
long long arp_check_start_ts; // TS of when we started the
// AS_COLLISION_CHECK state.
size_t reply_offset;
arp_state_t state;
unsigned int total_conflicts; // Total number of address conflicts on
// the interface. Never decreases.
int gw_check_initpings; // Initial count of ASEND_GW_PING when
// AS_GW_CHECK was entered.
uint16_t probe_wait_time; // Time to wait for a COLLISION_CHECK reply
// (in ms?).
bool using_bpf:1; // Is a BPF installed on the ARP socket?
bool relentless_def:1; // Don't give up defense no matter what.
bool router_replied:1;
bool server_replied:1;
};
static int gw_check_init_pingcount; // Initial count of ASEND_GW_PING when
// AS_GW_CHECK was entered.
static struct arp_data garp = {
.state = AS_NONE,
.wake_ts = { -1, -1, -1, -1, -1 },
.send_stats = {{0},{0},{0}},
.last_conflict_ts = 0,
.gw_check_initpings = 0,
.arp_check_start_ts = 0,
.total_conflicts = 0,
.probe_wait_time = 0,
.reply_offset = 0,
.using_bpf = false,
.relentless_def = false,
.router_replied = false,
.server_replied = false,
};
static uint16_t probe_wait_time; // Time to wait for a COLLISION_CHECK reply.
static long long arp_check_start_ts; // TS of when we started the
// AS_COLLISION_CHECK state.
void set_arp_relentless_def(void) { garp.relentless_def = true; }
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 char arp_router_has_replied;
static char arp_server_has_replied;
static struct arpMsg arpreply;
static size_t arpreply_offset;
static void arpreply_clear(void)
static void arp_reply_clear(void)
{
memset(&arpreply, 0, sizeof arpreply);
arpreply_offset = 0;
memset(&garp.reply, 0, sizeof garp.reply);
garp.reply_offset = 0;
}
void arp_reset_send_stats(void)
{
for (int i = 0; i < ASEND_MAX; ++i) {
arp_send_stats[i].ts = 0;
arp_send_stats[i].count = 0;
garp.send_stats[i].ts = 0;
garp.send_stats[i].count = 0;
}
}
@ -129,8 +143,8 @@ static int get_arp_basic_socket(void)
char resp;
int fd = request_sockd_fd("a", 1, &resp);
switch (resp) {
case 'A': using_arp_bpf = 1; break;
case 'a': using_arp_bpf = 0; break;
case 'A': garp.using_bpf = true; break;
case 'a': garp.using_bpf = false; break;
default: suicide("%s: (%s) expected a or A sockd reply but got %c",
client_config.interface, __func__, resp);
}
@ -150,8 +164,8 @@ static int get_arp_defense_socket(struct client_state_t *cs)
char resp;
int fd = request_sockd_fd(buf, buflen, &resp);
switch (resp) {
case 'D': using_arp_bpf = 1; break;
case 'd': using_arp_bpf = 0; break;
case 'D': garp.using_bpf = true; break;
case 'd': garp.using_bpf = false; break;
default: suicide("%s: (%s) expected d or D sockd reply but got %c",
client_config.interface, __func__, resp);
}
@ -180,7 +194,7 @@ static int arp_open_fd(struct client_state_t *cs, arp_state_t state)
return -1;
}
epoll_add(cs->epollFd, cs->arpFd);
arpreply_clear();
arp_reply_clear();
return 0;
}
@ -191,38 +205,38 @@ static void arp_min_close_fd(struct client_state_t *cs)
epoll_del(cs->epollFd, cs->arpFd);
close(cs->arpFd);
cs->arpFd = -1;
arpState = AS_NONE;
garp.state = AS_NONE;
}
static void arp_switch_state(struct client_state_t *cs, arp_state_t state)
{
if (arpState == state || arpState >= AS_MAX)
if (garp.state == state || garp.state >= AS_MAX)
return;
if (state == AS_NONE) {
arp_close_fd(cs);
return;
}
bool force_reopen = state == AS_DEFENSE || arpState == AS_DEFENSE;
bool force_reopen = state == AS_DEFENSE || garp.state == AS_DEFENSE;
if (force_reopen)
arp_min_close_fd(cs);
if (cs->arpFd < 0 || force_reopen) {
if (arp_open_fd(cs, state) < 0)
suicide("arp: Failed to open arpFd when changing state %u -> %u",
arpState, state);
garp.state, state);
}
arpState = state;
garp.state = state;
}
void arp_close_fd(struct client_state_t *cs)
{
arp_min_close_fd(cs);
for (int i = 0; i < AS_MAX; ++i)
arp_wake_ts[i] = -1;
garp.wake_ts[i] = -1;
}
static void arp_reopen_fd(struct client_state_t *cs)
{
arp_state_t prev_state = arpState;
arp_state_t prev_state = garp.state;
arp_min_close_fd(cs);
arp_switch_state(cs, prev_state);
}
@ -270,8 +284,8 @@ static int arp_ping(struct client_state_t *cs, uint32_t test_ip)
memcpy(arp.dip4, &test_ip, sizeof test_ip);
if (arp_send(cs, &arp) < 0)
return -1;
arp_send_stats[ASEND_GW_PING].count++;
arp_send_stats[ASEND_GW_PING].ts = curms();
garp.send_stats[ASEND_GW_PING].count++;
garp.send_stats[ASEND_GW_PING].ts = curms();
return 0;
}
@ -283,8 +297,8 @@ static int arp_ip_anon_ping(struct client_state_t *cs, uint32_t test_ip)
log_line("arp: Probing for hosts that may conflict with our lease...");
if (arp_send(cs, &arp) < 0)
return -1;
arp_send_stats[ASEND_COLLISION_CHECK].count++;
arp_send_stats[ASEND_COLLISION_CHECK].ts = curms();
garp.send_stats[ASEND_COLLISION_CHECK].count++;
garp.send_stats[ASEND_COLLISION_CHECK].ts = curms();
return 0;
}
@ -295,8 +309,8 @@ static int arp_announcement(struct client_state_t *cs)
memcpy(arp.dip4, &cs->clientAddr, 4);
if (arp_send(cs, &arp) < 0)
return -1;
arp_send_stats[ASEND_ANNOUNCE].count++;
arp_send_stats[ASEND_ANNOUNCE].ts = curms();
garp.send_stats[ASEND_ANNOUNCE].count++;
garp.send_stats[ASEND_ANNOUNCE].ts = curms();
return 0;
}
#undef BASE_ARPMSG
@ -304,38 +318,39 @@ static int arp_announcement(struct client_state_t *cs)
// 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));
memcpy(&garp.dhcp_packet, packet, sizeof (struct dhcpmsg));
arp_switch_state(cs, AS_COLLISION_CHECK);
if (arp_ip_anon_ping(cs, arp_dhcp_packet.yiaddr) < 0)
if (arp_ip_anon_ping(cs, garp.dhcp_packet.yiaddr) < 0)
return -1;
cs->arpPrevState = cs->dhcpState;
cs->dhcpState = DS_COLLISION_CHECK;
arp_check_start_ts = arp_send_stats[ASEND_COLLISION_CHECK].ts;
probe_wait_time = arp_probe_wait;
arp_wake_ts[AS_COLLISION_CHECK] = arp_check_start_ts + probe_wait_time;
garp.arp_check_start_ts = garp.send_stats[ASEND_COLLISION_CHECK].ts;
garp.probe_wait_time = arp_probe_wait;
garp.wake_ts[AS_COLLISION_CHECK] = garp.arp_check_start_ts
+ garp.probe_wait_time;
return 0;
}
// Callable only from DS_BOUND via state.c:ifup_action().
int arp_gw_check(struct client_state_t *cs)
{
if (arpState == AS_GW_CHECK) // Guard against state bounce.
if (garp.state == AS_GW_CHECK) // Guard against state bounce.
return 0;
gw_check_init_pingcount = arp_send_stats[ASEND_GW_PING].count;
arp_server_has_replied = 0;
garp.gw_check_initpings = garp.send_stats[ASEND_GW_PING].count;
garp.server_replied = false;
if (arp_ping(cs, cs->serverAddr) < 0)
return -1;
if (cs->routerAddr) {
arp_router_has_replied = 0;
garp.router_replied = false;
if (arp_ping(cs, cs->routerAddr) < 0)
return -1;
} else
arp_router_has_replied = 1;
garp.router_replied = true;
arp_switch_state(cs, AS_GW_CHECK);
cs->arpPrevState = cs->dhcpState;
cs->dhcpState = DS_BOUND_GW_CHECK;
arp_wake_ts[AS_GW_CHECK] =
arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
garp.wake_ts[AS_GW_CHECK] =
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
return 0;
}
@ -358,32 +373,32 @@ static int arp_get_gw_hwaddr(struct client_state_t *cs)
return -1;
} else
cs->got_router_arp = 1;
arp_wake_ts[AS_GW_QUERY] =
arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
garp.wake_ts[AS_GW_QUERY] =
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
return 0;
}
static void arp_failed(struct client_state_t *cs)
{
log_line("arp: Offered address is in use. Declining.");
send_decline(cs, arp_dhcp_packet.yiaddr);
arp_wake_ts[AS_COLLISION_CHECK] = -1;
reinit_selecting(cs, total_conflicts < MAX_CONFLICTS ?
send_decline(cs, garp.dhcp_packet.yiaddr);
garp.wake_ts[AS_COLLISION_CHECK] = -1;
reinit_selecting(cs, garp.total_conflicts < MAX_CONFLICTS ?
0 : RATE_LIMIT_INTERVAL);
}
static void arp_gw_failed(struct client_state_t *cs)
{
arp_wake_ts[AS_GW_CHECK] = -1;
garp.wake_ts[AS_GW_CHECK] = -1;
reinit_selecting(cs, 0);
}
static int act_if_arp_gw_failed(struct client_state_t *cs)
{
if (arp_send_stats[ASEND_GW_PING].count >= gw_check_init_pingcount + 6) {
if (arp_router_has_replied && !arp_server_has_replied)
if (garp.send_stats[ASEND_GW_PING].count >= garp.gw_check_initpings + 6) {
if (garp.router_replied && !garp.server_replied)
log_line("arp: DHCP server didn't reply. Getting new lease.");
else if (!arp_router_has_replied && arp_server_has_replied)
else if (!garp.router_replied && garp.server_replied)
log_line("arp: Gateway didn't reply. Getting new lease.");
else
log_line("arp: DHCP server and gateway didn't reply. Getting new lease.");
@ -401,20 +416,20 @@ void arp_set_defense_mode(struct client_state_t *cs)
void arp_success(struct client_state_t *cs)
{
char clibuf[INET_ADDRSTRLEN];
struct in_addr temp_addr = {.s_addr = arp_dhcp_packet.yiaddr};
struct in_addr temp_addr = {.s_addr = garp.dhcp_packet.yiaddr};
inet_ntop(AF_INET, &temp_addr, clibuf, sizeof clibuf);
log_line("Lease of %s obtained. Lease time is %ld seconds.",
clibuf, cs->lease);
cs->clientAddr = arp_dhcp_packet.yiaddr;
cs->clientAddr = garp.dhcp_packet.yiaddr;
cs->dhcpState = DS_BOUND;
cs->init = 0;
last_conflict_ts = 0;
arp_wake_ts[AS_COLLISION_CHECK] = -1;
ifchange_bind(cs, &arp_dhcp_packet);
garp.last_conflict_ts = 0;
garp.wake_ts[AS_COLLISION_CHECK] = -1;
ifchange_bind(cs, &garp.dhcp_packet);
if (cs->arpPrevState == DS_RENEWING || cs->arpPrevState == DS_REBINDING) {
arp_switch_state(cs, AS_DEFENSE);
} else {
cs->routerAddr = get_option_router(&arp_dhcp_packet);
cs->routerAddr = get_option_router(&garp.dhcp_packet);
arp_get_gw_hwaddr(cs);
}
set_listen_none(cs);
@ -432,7 +447,7 @@ static void arp_gw_success(struct client_state_t *cs)
arp_switch_state(cs, AS_DEFENSE);
arp_announcement(cs);
arp_wake_ts[AS_GW_CHECK] = -1;
garp.wake_ts[AS_GW_CHECK] = -1;
cs->dhcpState = cs->arpPrevState;
}
@ -496,10 +511,10 @@ static int arp_gen_probe_wait(struct client_state_t *cs)
static void arp_defense_timeout(struct client_state_t *cs, long long nowts)
{
(void)nowts; // Suppress warning; parameter necessary but unused.
if (arp_wake_ts[AS_DEFENSE] != -1) {
if (garp.wake_ts[AS_DEFENSE] != -1) {
log_line("arp: Defending our lease IP.");
arp_announcement(cs);
arp_wake_ts[AS_DEFENSE] = -1;
garp.wake_ts[AS_DEFENSE] = -1;
}
}
@ -509,32 +524,32 @@ static void arp_gw_check_timeout(struct client_state_t *cs, long long nowts)
if (act_if_arp_gw_failed(cs))
return;
long long rtts = arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
long long rtts = garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
if (nowts < rtts) {
arp_wake_ts[AS_GW_CHECK] = rtts;
garp.wake_ts[AS_GW_CHECK] = rtts;
return;
}
if (!arp_router_has_replied) {
if (!garp.router_replied) {
log_line("arp: Still waiting for gateway to reply to arp ping...");
if (arp_ping(cs, cs->routerAddr) < 0)
log_warning("arp: Failed to send ARP ping in retransmission.");
}
if (!arp_server_has_replied) {
if (!garp.server_replied) {
log_line("arp: Still waiting for DHCP server to reply to arp ping...");
if (arp_ping(cs, cs->serverAddr) < 0)
log_warning("arp: Failed to send ARP ping in retransmission.");
}
arp_wake_ts[AS_GW_CHECK] =
arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
garp.wake_ts[AS_GW_CHECK] =
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
}
static void arp_gw_query_timeout(struct client_state_t *cs, long long nowts)
{
arp_defense_timeout(cs, nowts);
long long rtts = arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
long long rtts = garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
if (nowts < rtts) {
arp_wake_ts[AS_GW_QUERY] = rtts;
garp.wake_ts[AS_GW_QUERY] = rtts;
return;
}
if (!cs->got_router_arp) {
@ -547,30 +562,30 @@ static void arp_gw_query_timeout(struct client_state_t *cs, long long nowts)
if (arp_ping(cs, cs->serverAddr) < 0)
log_warning("arp: Failed to send ARP ping in retransmission.");
}
arp_wake_ts[AS_GW_QUERY] =
arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
garp.wake_ts[AS_GW_QUERY] =
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
}
static void arp_collision_timeout(struct client_state_t *cs, long long nowts)
{
arp_defense_timeout(cs, nowts);
if (nowts >= arp_check_start_ts + ANNOUNCE_WAIT ||
arp_send_stats[ASEND_COLLISION_CHECK].count >= arp_probe_num) {
if (nowts >= garp.arp_check_start_ts + ANNOUNCE_WAIT ||
garp.send_stats[ASEND_COLLISION_CHECK].count >= arp_probe_num) {
arp_success(cs);
return;
}
long long rtts = arp_send_stats[ASEND_COLLISION_CHECK].ts +
probe_wait_time;
long long rtts = garp.send_stats[ASEND_COLLISION_CHECK].ts +
garp.probe_wait_time;
if (nowts < rtts) {
arp_wake_ts[AS_COLLISION_CHECK] = rtts;
garp.wake_ts[AS_COLLISION_CHECK] = rtts;
return;
}
if (arp_ip_anon_ping(cs, arp_dhcp_packet.yiaddr) < 0)
if (arp_ip_anon_ping(cs, garp.dhcp_packet.yiaddr) < 0)
log_warning("arp: Failed to send ARP ping in retransmission.");
probe_wait_time = arp_gen_probe_wait(cs);
arp_wake_ts[AS_COLLISION_CHECK] =
arp_send_stats[ASEND_COLLISION_CHECK].ts + probe_wait_time;
garp.probe_wait_time = arp_gen_probe_wait(cs);
garp.wake_ts[AS_COLLISION_CHECK] =
garp.send_stats[ASEND_COLLISION_CHECK].ts + garp.probe_wait_time;
}
static void arp_do_defense(struct client_state_t *cs)
@ -578,43 +593,43 @@ static void arp_do_defense(struct client_state_t *cs)
// Even though the BPF will usually catch this case, sometimes there are
// packets still in the socket buffer that arrived before the defense
// BPF was installed, so it's necessary to check here.
if (!arp_validate_bpf_defense(cs, &arpreply))
if (!arp_validate_bpf_defense(cs, &garp.reply))
return;
log_line("arp: Detected a peer attempting to use our IP!");
long long nowts = curms();
arp_wake_ts[AS_DEFENSE] = -1;
if (!last_conflict_ts ||
nowts - last_conflict_ts < DEFEND_INTERVAL) {
garp.wake_ts[AS_DEFENSE] = -1;
if (!garp.last_conflict_ts ||
nowts - garp.last_conflict_ts < DEFEND_INTERVAL) {
log_line("arp: Defending our lease IP.");
arp_announcement(cs);
} else if (!arp_relentless_def) {
} else if (!garp.relentless_def) {
log_line("arp: Conflicting peer is persistent. Requesting new lease.");
send_release(cs);
reinit_selecting(cs, 0);
} else {
arp_wake_ts[AS_DEFENSE] =
arp_send_stats[ASEND_ANNOUNCE].ts + DEFEND_INTERVAL;
garp.wake_ts[AS_DEFENSE] =
garp.send_stats[ASEND_ANNOUNCE].ts + DEFEND_INTERVAL;
}
total_conflicts++;
last_conflict_ts = nowts;
garp.total_conflicts++;
garp.last_conflict_ts = nowts;
}
static void arp_do_gw_query_done(struct client_state_t *cs)
{
arp_wake_ts[AS_GW_QUERY] = -1;
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(&arpreply)) {
if (!arp_is_query_reply(&garp.reply)) {
arp_do_defense(cs);
return;
}
if (!memcmp(arpreply.sip4, &cs->routerAddr, 4)) {
memcpy(cs->routerArp, arpreply.smac, 6);
if (!memcmp(garp.reply.sip4, &cs->routerAddr, 4)) {
memcpy(cs->routerArp, garp.reply.smac, 6);
log_line("arp: Gateway hardware address %02x:%02x:%02x:%02x:%02x:%02x",
cs->routerArp[0], cs->routerArp[1],
cs->routerArp[2], cs->routerArp[3],
@ -626,9 +641,9 @@ static void arp_do_gw_query(struct client_state_t *cs)
arp_do_gw_query_done(cs);
return;
}
if (!memcmp(arpreply.sip4, &cs->serverAddr, 4)) {
if (!memcmp(garp.reply.sip4, &cs->serverAddr, 4)) {
server_is_router:
memcpy(cs->serverArp, arpreply.smac, 6);
memcpy(cs->serverArp, garp.reply.smac, 6);
log_line("arp: DHCP Server hardware address %02x:%02x:%02x:%02x:%02x:%02x",
cs->serverArp[0], cs->serverArp[1],
cs->serverArp[2], cs->serverArp[3],
@ -643,29 +658,29 @@ server_is_router:
static void arp_do_collision_check(struct client_state_t *cs)
{
if (!arp_is_query_reply(&arpreply))
if (!arp_is_query_reply(&garp.reply))
return;
// If this packet was sent from our lease IP, and does not have a
// MAC address matching our own (the latter check guards against stupid
// hubs or repeaters), then it's a conflict and thus a failure.
if (!memcmp(arpreply.sip4, &arp_dhcp_packet.yiaddr, 4) &&
!memcmp(client_config.arp, arpreply.smac, 6)) {
total_conflicts++;
if (!memcmp(garp.reply.sip4, &garp.dhcp_packet.yiaddr, 4) &&
!memcmp(client_config.arp, garp.reply.smac, 6)) {
garp.total_conflicts++;
arp_failed(cs);
}
}
static void arp_do_gw_check(struct client_state_t *cs)
{
if (!arp_is_query_reply(&arpreply))
if (!arp_is_query_reply(&garp.reply))
return;
if (!memcmp(arpreply.sip4, &cs->routerAddr, 4)) {
if (!memcmp(garp.reply.sip4, &cs->routerAddr, 4)) {
// Success only if the router/gw MAC matches stored value
if (!memcmp(cs->routerArp, arpreply.smac, 6)) {
arp_router_has_replied = 1;
if (!memcmp(cs->routerArp, garp.reply.smac, 6)) {
garp.router_replied = true;
if (cs->routerAddr == cs->serverAddr)
goto server_is_router;
if (arp_server_has_replied)
if (garp.server_replied)
arp_gw_success(cs);
} else {
log_line("arp: Gateway is different. Getting a new lease.");
@ -673,12 +688,12 @@ static void arp_do_gw_check(struct client_state_t *cs)
}
return;
}
if (!memcmp(arpreply.sip4, &cs->serverAddr, 4)) {
if (!memcmp(garp.reply.sip4, &cs->serverAddr, 4)) {
server_is_router:
// Success only if the server MAC matches stored value
if (!memcmp(cs->serverArp, arpreply.smac, 6)) {
arp_server_has_replied = 1;
if (arp_router_has_replied)
if (!memcmp(cs->serverArp, garp.reply.smac, 6)) {
garp.server_replied = true;
if (garp.router_replied)
arp_gw_success(cs);
} else {
log_line("arp: DHCP server is different. Getting a new lease.");
@ -689,7 +704,7 @@ server_is_router:
static void arp_do_invalid(struct client_state_t *cs)
{
log_error("handle_arp_response: called in invalid state %u", arpState);
log_error("handle_arp_response: called in invalid state %u", garp.state);
arp_close_fd(cs);
}
@ -710,18 +725,18 @@ static const arp_state_fn_t arp_states[] = {
void handle_arp_response(struct client_state_t *cs)
{
ssize_t r = 0;
if (arpreply_offset < sizeof arpreply) {
r = safe_read(cs->arpFd, (char *)&arpreply + arpreply_offset,
sizeof arpreply - arpreply_offset);
if (garp.reply_offset < sizeof garp.reply) {
r = safe_read(cs->arpFd, (char *)&garp.reply + garp.reply_offset,
sizeof garp.reply - garp.reply_offset);
if (r < 0) {
log_error("arp: ARP response read failed: %s", strerror(errno));
switch (arpState) {
switch (garp.state) {
case AS_COLLISION_CHECK: arp_failed(cs); break;
case AS_GW_CHECK: arp_gw_failed(cs); break;
default: arp_reopen_fd(cs); break;
}
} else
arpreply_offset += (size_t)r;
garp.reply_offset += (size_t)r;
}
if (r <= 0) {
@ -729,37 +744,38 @@ void handle_arp_response(struct client_state_t *cs)
return;
}
if (arpreply_offset < ARP_MSG_SIZE)
if (garp.reply_offset < ARP_MSG_SIZE)
return;
// Emulate the BPF filters if they are not in use.
if (!using_arp_bpf && (!arp_validate_bpf(&arpreply) ||
(arpState == AS_DEFENSE &&
!arp_validate_bpf_defense(cs, &arpreply)))) {
arpreply_clear();
if (!garp.using_bpf &&
(!arp_validate_bpf(&garp.reply) ||
(garp.state == AS_DEFENSE &&
!arp_validate_bpf_defense(cs, &garp.reply)))) {
arp_reply_clear();
return;
}
if (arp_states[arpState].packet_fn)
arp_states[arpState].packet_fn(cs);
arpreply_clear();
if (arp_states[garp.state].packet_fn)
arp_states[garp.state].packet_fn(cs);
arp_reply_clear();
}
// Perform retransmission if necessary.
void handle_arp_timeout(struct client_state_t *cs, long long nowts)
{
if (arp_states[arpState].timeout_fn)
arp_states[arpState].timeout_fn(cs, nowts);
if (arp_states[garp.state].timeout_fn)
arp_states[garp.state].timeout_fn(cs, nowts);
}
long long arp_get_wake_ts(void)
{
long long mt = -1;
for (int i = 0; i < AS_MAX; ++i) {
if (arp_wake_ts[i] < 0)
if (garp.wake_ts[i] < 0)
continue;
if (mt < 0 || mt > arp_wake_ts[i])
mt = arp_wake_ts[i];
if (mt < 0 || mt > garp.wake_ts[i])
mt = garp.wake_ts[i];
}
return mt;
}

View File

@ -56,8 +56,8 @@ extern int arp_probe_wait;
extern int arp_probe_num;
extern int arp_probe_min;
extern int arp_probe_max;
extern int arp_relentless_def;
void set_arp_relentless_def(void);
void arp_reset_send_stats(void);
void arp_close_fd(struct client_state_t *cs);
int arp_check(struct client_state_t *cs, struct dhcpmsg *packet);

View File

@ -538,7 +538,7 @@ static void parse_program_options(int argc, char *argv[])
seccomp_enforce = true;
break;
case 'd':
arp_relentless_def = 1;
set_arp_relentless_def();
break;
case 'w':
case 'W': {