Consolidate all of the global static variables in arp.c into a single
struct, and use booleans where appropriate.
This commit is contained in:
parent
a86363f248
commit
e2ee728982
296
src/arp.c
296
src/arp.c
@ -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 RATE_LIMIT_INTERVAL 60000 // delay between successive attempts
|
||||||
#define DEFEND_INTERVAL 10000 // minimum interval between defensive ARPs
|
#define DEFEND_INTERVAL 10000 // minimum interval between defensive ARPs
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AS_NONE = 0, // Nothing to react to wrt ARP
|
AS_NONE = 0, // Nothing to react to wrt ARP
|
||||||
AS_COLLISION_CHECK, // Checking to see if another host has our IP before
|
AS_COLLISION_CHECK, // Checking to see if another host has our IP before
|
||||||
@ -73,8 +72,6 @@ typedef enum {
|
|||||||
AS_MAX,
|
AS_MAX,
|
||||||
} arp_state_t;
|
} arp_state_t;
|
||||||
|
|
||||||
static long long arp_wake_ts[AS_MAX] = { -1, -1, -1, -1, -1 };
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ASEND_COLLISION_CHECK,
|
ASEND_COLLISION_CHECK,
|
||||||
ASEND_GW_PING,
|
ASEND_GW_PING,
|
||||||
@ -82,45 +79,62 @@ typedef enum {
|
|||||||
ASEND_MAX,
|
ASEND_MAX,
|
||||||
} arp_send_t;
|
} arp_send_t;
|
||||||
|
|
||||||
static arp_state_t arpState;
|
|
||||||
struct arp_stats {
|
struct arp_stats {
|
||||||
long long ts;
|
long long ts;
|
||||||
int count;
|
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.
|
struct arp_data {
|
||||||
static long long last_conflict_ts; // TS of the last conflicting ARP seen.
|
struct dhcpmsg dhcp_packet; // Used only for AS_COLLISION_CHECK
|
||||||
|
struct arpMsg reply;
|
||||||
static int gw_check_init_pingcount; // Initial count of ASEND_GW_PING when
|
struct arp_stats send_stats[ASEND_MAX];
|
||||||
// AS_GW_CHECK was entered.
|
long long wake_ts[AS_MAX];
|
||||||
|
long long last_conflict_ts; // TS of the last conflicting ARP seen.
|
||||||
static uint16_t probe_wait_time; // Time to wait for a COLLISION_CHECK reply.
|
long long arp_check_start_ts; // TS of when we started the
|
||||||
static long long arp_check_start_ts; // TS of when we started the
|
|
||||||
// AS_COLLISION_CHECK state.
|
// AS_COLLISION_CHECK state.
|
||||||
|
size_t reply_offset;
|
||||||
static unsigned int total_conflicts; // Total number of address conflicts on
|
arp_state_t state;
|
||||||
|
unsigned int total_conflicts; // Total number of address conflicts on
|
||||||
// the interface. Never decreases.
|
// 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 struct dhcpmsg arp_dhcp_packet; // Used only for AS_COLLISION_CHECK
|
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 char arp_router_has_replied;
|
void set_arp_relentless_def(void) { garp.relentless_def = true; }
|
||||||
static char arp_server_has_replied;
|
|
||||||
|
|
||||||
static struct arpMsg arpreply;
|
static void arp_reply_clear(void)
|
||||||
static size_t arpreply_offset;
|
|
||||||
static void arpreply_clear(void)
|
|
||||||
{
|
{
|
||||||
memset(&arpreply, 0, sizeof arpreply);
|
memset(&garp.reply, 0, sizeof garp.reply);
|
||||||
arpreply_offset = 0;
|
garp.reply_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void arp_reset_send_stats(void)
|
void arp_reset_send_stats(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < ASEND_MAX; ++i) {
|
for (int i = 0; i < ASEND_MAX; ++i) {
|
||||||
arp_send_stats[i].ts = 0;
|
garp.send_stats[i].ts = 0;
|
||||||
arp_send_stats[i].count = 0;
|
garp.send_stats[i].count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,8 +143,8 @@ static int get_arp_basic_socket(void)
|
|||||||
char resp;
|
char resp;
|
||||||
int fd = request_sockd_fd("a", 1, &resp);
|
int fd = request_sockd_fd("a", 1, &resp);
|
||||||
switch (resp) {
|
switch (resp) {
|
||||||
case 'A': using_arp_bpf = 1; break;
|
case 'A': garp.using_bpf = true; break;
|
||||||
case 'a': using_arp_bpf = 0; break;
|
case 'a': garp.using_bpf = false; break;
|
||||||
default: suicide("%s: (%s) expected a or A sockd reply but got %c",
|
default: suicide("%s: (%s) expected a or A sockd reply but got %c",
|
||||||
client_config.interface, __func__, resp);
|
client_config.interface, __func__, resp);
|
||||||
}
|
}
|
||||||
@ -150,8 +164,8 @@ static int get_arp_defense_socket(struct client_state_t *cs)
|
|||||||
char resp;
|
char resp;
|
||||||
int fd = request_sockd_fd(buf, buflen, &resp);
|
int fd = request_sockd_fd(buf, buflen, &resp);
|
||||||
switch (resp) {
|
switch (resp) {
|
||||||
case 'D': using_arp_bpf = 1; break;
|
case 'D': garp.using_bpf = true; break;
|
||||||
case 'd': using_arp_bpf = 0; break;
|
case 'd': garp.using_bpf = false; break;
|
||||||
default: suicide("%s: (%s) expected d or D sockd reply but got %c",
|
default: suicide("%s: (%s) expected d or D sockd reply but got %c",
|
||||||
client_config.interface, __func__, resp);
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
epoll_add(cs->epollFd, cs->arpFd);
|
epoll_add(cs->epollFd, cs->arpFd);
|
||||||
arpreply_clear();
|
arp_reply_clear();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,38 +205,38 @@ static void arp_min_close_fd(struct client_state_t *cs)
|
|||||||
epoll_del(cs->epollFd, cs->arpFd);
|
epoll_del(cs->epollFd, cs->arpFd);
|
||||||
close(cs->arpFd);
|
close(cs->arpFd);
|
||||||
cs->arpFd = -1;
|
cs->arpFd = -1;
|
||||||
arpState = AS_NONE;
|
garp.state = AS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_switch_state(struct client_state_t *cs, arp_state_t state)
|
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;
|
return;
|
||||||
if (state == AS_NONE) {
|
if (state == AS_NONE) {
|
||||||
arp_close_fd(cs);
|
arp_close_fd(cs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool force_reopen = state == AS_DEFENSE || arpState == AS_DEFENSE;
|
bool force_reopen = state == AS_DEFENSE || garp.state == AS_DEFENSE;
|
||||||
if (force_reopen)
|
if (force_reopen)
|
||||||
arp_min_close_fd(cs);
|
arp_min_close_fd(cs);
|
||||||
if (cs->arpFd < 0 || force_reopen) {
|
if (cs->arpFd < 0 || force_reopen) {
|
||||||
if (arp_open_fd(cs, state) < 0)
|
if (arp_open_fd(cs, state) < 0)
|
||||||
suicide("arp: Failed to open arpFd when changing state %u -> %u",
|
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)
|
void arp_close_fd(struct client_state_t *cs)
|
||||||
{
|
{
|
||||||
arp_min_close_fd(cs);
|
arp_min_close_fd(cs);
|
||||||
for (int i = 0; i < AS_MAX; ++i)
|
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)
|
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_min_close_fd(cs);
|
||||||
arp_switch_state(cs, prev_state);
|
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);
|
memcpy(arp.dip4, &test_ip, sizeof test_ip);
|
||||||
if (arp_send(cs, &arp) < 0)
|
if (arp_send(cs, &arp) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
arp_send_stats[ASEND_GW_PING].count++;
|
garp.send_stats[ASEND_GW_PING].count++;
|
||||||
arp_send_stats[ASEND_GW_PING].ts = curms();
|
garp.send_stats[ASEND_GW_PING].ts = curms();
|
||||||
return 0;
|
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...");
|
log_line("arp: Probing for hosts that may conflict with our lease...");
|
||||||
if (arp_send(cs, &arp) < 0)
|
if (arp_send(cs, &arp) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
arp_send_stats[ASEND_COLLISION_CHECK].count++;
|
garp.send_stats[ASEND_COLLISION_CHECK].count++;
|
||||||
arp_send_stats[ASEND_COLLISION_CHECK].ts = curms();
|
garp.send_stats[ASEND_COLLISION_CHECK].ts = curms();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,8 +309,8 @@ static int arp_announcement(struct client_state_t *cs)
|
|||||||
memcpy(arp.dip4, &cs->clientAddr, 4);
|
memcpy(arp.dip4, &cs->clientAddr, 4);
|
||||||
if (arp_send(cs, &arp) < 0)
|
if (arp_send(cs, &arp) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
arp_send_stats[ASEND_ANNOUNCE].count++;
|
garp.send_stats[ASEND_ANNOUNCE].count++;
|
||||||
arp_send_stats[ASEND_ANNOUNCE].ts = curms();
|
garp.send_stats[ASEND_ANNOUNCE].ts = curms();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#undef BASE_ARPMSG
|
#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()
|
// Callable from DS_REQUESTING, DS_RENEWING, or DS_REBINDING via an_packet()
|
||||||
int arp_check(struct client_state_t *cs, struct dhcpmsg *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);
|
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;
|
return -1;
|
||||||
cs->arpPrevState = cs->dhcpState;
|
cs->arpPrevState = cs->dhcpState;
|
||||||
cs->dhcpState = DS_COLLISION_CHECK;
|
cs->dhcpState = DS_COLLISION_CHECK;
|
||||||
arp_check_start_ts = arp_send_stats[ASEND_COLLISION_CHECK].ts;
|
garp.arp_check_start_ts = garp.send_stats[ASEND_COLLISION_CHECK].ts;
|
||||||
probe_wait_time = arp_probe_wait;
|
garp.probe_wait_time = arp_probe_wait;
|
||||||
arp_wake_ts[AS_COLLISION_CHECK] = arp_check_start_ts + probe_wait_time;
|
garp.wake_ts[AS_COLLISION_CHECK] = garp.arp_check_start_ts
|
||||||
|
+ garp.probe_wait_time;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callable only from DS_BOUND via state.c:ifup_action().
|
// Callable only from DS_BOUND via state.c:ifup_action().
|
||||||
int arp_gw_check(struct client_state_t *cs)
|
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;
|
return 0;
|
||||||
gw_check_init_pingcount = arp_send_stats[ASEND_GW_PING].count;
|
garp.gw_check_initpings = garp.send_stats[ASEND_GW_PING].count;
|
||||||
arp_server_has_replied = 0;
|
garp.server_replied = false;
|
||||||
if (arp_ping(cs, cs->serverAddr) < 0)
|
if (arp_ping(cs, cs->serverAddr) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (cs->routerAddr) {
|
if (cs->routerAddr) {
|
||||||
arp_router_has_replied = 0;
|
garp.router_replied = false;
|
||||||
if (arp_ping(cs, cs->routerAddr) < 0)
|
if (arp_ping(cs, cs->routerAddr) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
} else
|
} else
|
||||||
arp_router_has_replied = 1;
|
garp.router_replied = true;
|
||||||
arp_switch_state(cs, AS_GW_CHECK);
|
arp_switch_state(cs, AS_GW_CHECK);
|
||||||
cs->arpPrevState = cs->dhcpState;
|
cs->arpPrevState = cs->dhcpState;
|
||||||
cs->dhcpState = DS_BOUND_GW_CHECK;
|
cs->dhcpState = DS_BOUND_GW_CHECK;
|
||||||
arp_wake_ts[AS_GW_CHECK] =
|
garp.wake_ts[AS_GW_CHECK] =
|
||||||
arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
|
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,32 +373,32 @@ static int arp_get_gw_hwaddr(struct client_state_t *cs)
|
|||||||
return -1;
|
return -1;
|
||||||
} else
|
} else
|
||||||
cs->got_router_arp = 1;
|
cs->got_router_arp = 1;
|
||||||
arp_wake_ts[AS_GW_QUERY] =
|
garp.wake_ts[AS_GW_QUERY] =
|
||||||
arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
|
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_failed(struct client_state_t *cs)
|
static void arp_failed(struct client_state_t *cs)
|
||||||
{
|
{
|
||||||
log_line("arp: Offered address is in use. Declining.");
|
log_line("arp: Offered address is in use. Declining.");
|
||||||
send_decline(cs, arp_dhcp_packet.yiaddr);
|
send_decline(cs, garp.dhcp_packet.yiaddr);
|
||||||
arp_wake_ts[AS_COLLISION_CHECK] = -1;
|
garp.wake_ts[AS_COLLISION_CHECK] = -1;
|
||||||
reinit_selecting(cs, total_conflicts < MAX_CONFLICTS ?
|
reinit_selecting(cs, garp.total_conflicts < MAX_CONFLICTS ?
|
||||||
0 : RATE_LIMIT_INTERVAL);
|
0 : RATE_LIMIT_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_gw_failed(struct client_state_t *cs)
|
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);
|
reinit_selecting(cs, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int act_if_arp_gw_failed(struct client_state_t *cs)
|
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 (garp.send_stats[ASEND_GW_PING].count >= garp.gw_check_initpings + 6) {
|
||||||
if (arp_router_has_replied && !arp_server_has_replied)
|
if (garp.router_replied && !garp.server_replied)
|
||||||
log_line("arp: DHCP server didn't reply. Getting new lease.");
|
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.");
|
log_line("arp: Gateway didn't reply. Getting new lease.");
|
||||||
else
|
else
|
||||||
log_line("arp: DHCP server and gateway didn't reply. Getting new lease.");
|
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)
|
void arp_success(struct client_state_t *cs)
|
||||||
{
|
{
|
||||||
char clibuf[INET_ADDRSTRLEN];
|
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);
|
inet_ntop(AF_INET, &temp_addr, clibuf, sizeof clibuf);
|
||||||
log_line("Lease of %s obtained. Lease time is %ld seconds.",
|
log_line("Lease of %s obtained. Lease time is %ld seconds.",
|
||||||
clibuf, cs->lease);
|
clibuf, cs->lease);
|
||||||
cs->clientAddr = arp_dhcp_packet.yiaddr;
|
cs->clientAddr = garp.dhcp_packet.yiaddr;
|
||||||
cs->dhcpState = DS_BOUND;
|
cs->dhcpState = DS_BOUND;
|
||||||
cs->init = 0;
|
cs->init = 0;
|
||||||
last_conflict_ts = 0;
|
garp.last_conflict_ts = 0;
|
||||||
arp_wake_ts[AS_COLLISION_CHECK] = -1;
|
garp.wake_ts[AS_COLLISION_CHECK] = -1;
|
||||||
ifchange_bind(cs, &arp_dhcp_packet);
|
ifchange_bind(cs, &garp.dhcp_packet);
|
||||||
if (cs->arpPrevState == DS_RENEWING || cs->arpPrevState == DS_REBINDING) {
|
if (cs->arpPrevState == DS_RENEWING || cs->arpPrevState == DS_REBINDING) {
|
||||||
arp_switch_state(cs, AS_DEFENSE);
|
arp_switch_state(cs, AS_DEFENSE);
|
||||||
} else {
|
} else {
|
||||||
cs->routerAddr = get_option_router(&arp_dhcp_packet);
|
cs->routerAddr = get_option_router(&garp.dhcp_packet);
|
||||||
arp_get_gw_hwaddr(cs);
|
arp_get_gw_hwaddr(cs);
|
||||||
}
|
}
|
||||||
set_listen_none(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_switch_state(cs, AS_DEFENSE);
|
||||||
arp_announcement(cs);
|
arp_announcement(cs);
|
||||||
|
|
||||||
arp_wake_ts[AS_GW_CHECK] = -1;
|
garp.wake_ts[AS_GW_CHECK] = -1;
|
||||||
cs->dhcpState = cs->arpPrevState;
|
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)
|
static void arp_defense_timeout(struct client_state_t *cs, long long nowts)
|
||||||
{
|
{
|
||||||
(void)nowts; // Suppress warning; parameter necessary but unused.
|
(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.");
|
log_line("arp: Defending our lease IP.");
|
||||||
arp_announcement(cs);
|
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))
|
if (act_if_arp_gw_failed(cs))
|
||||||
return;
|
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) {
|
if (nowts < rtts) {
|
||||||
arp_wake_ts[AS_GW_CHECK] = rtts;
|
garp.wake_ts[AS_GW_CHECK] = rtts;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!arp_router_has_replied) {
|
if (!garp.router_replied) {
|
||||||
log_line("arp: Still waiting for gateway to reply to arp ping...");
|
log_line("arp: Still waiting for gateway to reply to arp ping...");
|
||||||
if (arp_ping(cs, cs->routerAddr) < 0)
|
if (arp_ping(cs, cs->routerAddr) < 0)
|
||||||
log_warning("arp: Failed to send ARP ping in retransmission.");
|
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...");
|
log_line("arp: Still waiting for DHCP server to reply to arp ping...");
|
||||||
if (arp_ping(cs, cs->serverAddr) < 0)
|
if (arp_ping(cs, cs->serverAddr) < 0)
|
||||||
log_warning("arp: Failed to send ARP ping in retransmission.");
|
log_warning("arp: Failed to send ARP ping in retransmission.");
|
||||||
}
|
}
|
||||||
arp_wake_ts[AS_GW_CHECK] =
|
garp.wake_ts[AS_GW_CHECK] =
|
||||||
arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
|
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_gw_query_timeout(struct client_state_t *cs, long long nowts)
|
static void arp_gw_query_timeout(struct client_state_t *cs, long long nowts)
|
||||||
{
|
{
|
||||||
arp_defense_timeout(cs, 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) {
|
if (nowts < rtts) {
|
||||||
arp_wake_ts[AS_GW_QUERY] = rtts;
|
garp.wake_ts[AS_GW_QUERY] = rtts;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!cs->got_router_arp) {
|
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)
|
if (arp_ping(cs, cs->serverAddr) < 0)
|
||||||
log_warning("arp: Failed to send ARP ping in retransmission.");
|
log_warning("arp: Failed to send ARP ping in retransmission.");
|
||||||
}
|
}
|
||||||
arp_wake_ts[AS_GW_QUERY] =
|
garp.wake_ts[AS_GW_QUERY] =
|
||||||
arp_send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
|
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_collision_timeout(struct client_state_t *cs, long long nowts)
|
static void arp_collision_timeout(struct client_state_t *cs, long long nowts)
|
||||||
{
|
{
|
||||||
arp_defense_timeout(cs, nowts);
|
arp_defense_timeout(cs, nowts);
|
||||||
|
|
||||||
if (nowts >= arp_check_start_ts + ANNOUNCE_WAIT ||
|
if (nowts >= garp.arp_check_start_ts + ANNOUNCE_WAIT ||
|
||||||
arp_send_stats[ASEND_COLLISION_CHECK].count >= arp_probe_num) {
|
garp.send_stats[ASEND_COLLISION_CHECK].count >= arp_probe_num) {
|
||||||
arp_success(cs);
|
arp_success(cs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long long rtts = arp_send_stats[ASEND_COLLISION_CHECK].ts +
|
long long rtts = garp.send_stats[ASEND_COLLISION_CHECK].ts +
|
||||||
probe_wait_time;
|
garp.probe_wait_time;
|
||||||
if (nowts < rtts) {
|
if (nowts < rtts) {
|
||||||
arp_wake_ts[AS_COLLISION_CHECK] = rtts;
|
garp.wake_ts[AS_COLLISION_CHECK] = rtts;
|
||||||
return;
|
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.");
|
log_warning("arp: Failed to send ARP ping in retransmission.");
|
||||||
probe_wait_time = arp_gen_probe_wait(cs);
|
garp.probe_wait_time = arp_gen_probe_wait(cs);
|
||||||
arp_wake_ts[AS_COLLISION_CHECK] =
|
garp.wake_ts[AS_COLLISION_CHECK] =
|
||||||
arp_send_stats[ASEND_COLLISION_CHECK].ts + probe_wait_time;
|
garp.send_stats[ASEND_COLLISION_CHECK].ts + garp.probe_wait_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_do_defense(struct client_state_t *cs)
|
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
|
// Even though the BPF will usually catch this case, sometimes there are
|
||||||
// packets still in the socket buffer that arrived before the defense
|
// packets still in the socket buffer that arrived before the defense
|
||||||
// BPF was installed, so it's necessary to check here.
|
// 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;
|
return;
|
||||||
|
|
||||||
log_line("arp: Detected a peer attempting to use our IP!");
|
log_line("arp: Detected a peer attempting to use our IP!");
|
||||||
long long nowts = curms();
|
long long nowts = curms();
|
||||||
arp_wake_ts[AS_DEFENSE] = -1;
|
garp.wake_ts[AS_DEFENSE] = -1;
|
||||||
if (!last_conflict_ts ||
|
if (!garp.last_conflict_ts ||
|
||||||
nowts - last_conflict_ts < DEFEND_INTERVAL) {
|
nowts - garp.last_conflict_ts < DEFEND_INTERVAL) {
|
||||||
log_line("arp: Defending our lease IP.");
|
log_line("arp: Defending our lease IP.");
|
||||||
arp_announcement(cs);
|
arp_announcement(cs);
|
||||||
} else if (!arp_relentless_def) {
|
} else if (!garp.relentless_def) {
|
||||||
log_line("arp: Conflicting peer is persistent. Requesting new lease.");
|
log_line("arp: Conflicting peer is persistent. Requesting new lease.");
|
||||||
send_release(cs);
|
send_release(cs);
|
||||||
reinit_selecting(cs, 0);
|
reinit_selecting(cs, 0);
|
||||||
} else {
|
} else {
|
||||||
arp_wake_ts[AS_DEFENSE] =
|
garp.wake_ts[AS_DEFENSE] =
|
||||||
arp_send_stats[ASEND_ANNOUNCE].ts + DEFEND_INTERVAL;
|
garp.send_stats[ASEND_ANNOUNCE].ts + DEFEND_INTERVAL;
|
||||||
}
|
}
|
||||||
total_conflicts++;
|
garp.total_conflicts++;
|
||||||
last_conflict_ts = nowts;
|
garp.last_conflict_ts = nowts;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_do_gw_query_done(struct client_state_t *cs)
|
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_switch_state(cs, AS_DEFENSE);
|
||||||
arp_announcement(cs); // Do a second announcement.
|
arp_announcement(cs); // Do a second announcement.
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_do_gw_query(struct client_state_t *cs)
|
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);
|
arp_do_defense(cs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!memcmp(arpreply.sip4, &cs->routerAddr, 4)) {
|
if (!memcmp(garp.reply.sip4, &cs->routerAddr, 4)) {
|
||||||
memcpy(cs->routerArp, arpreply.smac, 6);
|
memcpy(cs->routerArp, garp.reply.smac, 6);
|
||||||
log_line("arp: Gateway hardware address %02x:%02x:%02x:%02x:%02x:%02x",
|
log_line("arp: Gateway hardware address %02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
cs->routerArp[0], cs->routerArp[1],
|
cs->routerArp[0], cs->routerArp[1],
|
||||||
cs->routerArp[2], cs->routerArp[3],
|
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);
|
arp_do_gw_query_done(cs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!memcmp(arpreply.sip4, &cs->serverAddr, 4)) {
|
if (!memcmp(garp.reply.sip4, &cs->serverAddr, 4)) {
|
||||||
server_is_router:
|
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",
|
log_line("arp: DHCP Server hardware address %02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
cs->serverArp[0], cs->serverArp[1],
|
cs->serverArp[0], cs->serverArp[1],
|
||||||
cs->serverArp[2], cs->serverArp[3],
|
cs->serverArp[2], cs->serverArp[3],
|
||||||
@ -643,29 +658,29 @@ server_is_router:
|
|||||||
|
|
||||||
static void arp_do_collision_check(struct client_state_t *cs)
|
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;
|
return;
|
||||||
// If this packet was sent from our lease IP, and does not have a
|
// 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
|
// MAC address matching our own (the latter check guards against stupid
|
||||||
// hubs or repeaters), then it's a conflict and thus a failure.
|
// hubs or repeaters), then it's a conflict and thus a failure.
|
||||||
if (!memcmp(arpreply.sip4, &arp_dhcp_packet.yiaddr, 4) &&
|
if (!memcmp(garp.reply.sip4, &garp.dhcp_packet.yiaddr, 4) &&
|
||||||
!memcmp(client_config.arp, arpreply.smac, 6)) {
|
!memcmp(client_config.arp, garp.reply.smac, 6)) {
|
||||||
total_conflicts++;
|
garp.total_conflicts++;
|
||||||
arp_failed(cs);
|
arp_failed(cs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_do_gw_check(struct client_state_t *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;
|
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
|
// Success only if the router/gw MAC matches stored value
|
||||||
if (!memcmp(cs->routerArp, arpreply.smac, 6)) {
|
if (!memcmp(cs->routerArp, garp.reply.smac, 6)) {
|
||||||
arp_router_has_replied = 1;
|
garp.router_replied = true;
|
||||||
if (cs->routerAddr == cs->serverAddr)
|
if (cs->routerAddr == cs->serverAddr)
|
||||||
goto server_is_router;
|
goto server_is_router;
|
||||||
if (arp_server_has_replied)
|
if (garp.server_replied)
|
||||||
arp_gw_success(cs);
|
arp_gw_success(cs);
|
||||||
} else {
|
} else {
|
||||||
log_line("arp: Gateway is different. Getting a new lease.");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (!memcmp(arpreply.sip4, &cs->serverAddr, 4)) {
|
if (!memcmp(garp.reply.sip4, &cs->serverAddr, 4)) {
|
||||||
server_is_router:
|
server_is_router:
|
||||||
// Success only if the server MAC matches stored value
|
// Success only if the server MAC matches stored value
|
||||||
if (!memcmp(cs->serverArp, arpreply.smac, 6)) {
|
if (!memcmp(cs->serverArp, garp.reply.smac, 6)) {
|
||||||
arp_server_has_replied = 1;
|
garp.server_replied = true;
|
||||||
if (arp_router_has_replied)
|
if (garp.router_replied)
|
||||||
arp_gw_success(cs);
|
arp_gw_success(cs);
|
||||||
} else {
|
} else {
|
||||||
log_line("arp: DHCP server is different. Getting a new lease.");
|
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)
|
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);
|
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)
|
void handle_arp_response(struct client_state_t *cs)
|
||||||
{
|
{
|
||||||
ssize_t r = 0;
|
ssize_t r = 0;
|
||||||
if (arpreply_offset < sizeof arpreply) {
|
if (garp.reply_offset < sizeof garp.reply) {
|
||||||
r = safe_read(cs->arpFd, (char *)&arpreply + arpreply_offset,
|
r = safe_read(cs->arpFd, (char *)&garp.reply + garp.reply_offset,
|
||||||
sizeof arpreply - arpreply_offset);
|
sizeof garp.reply - garp.reply_offset);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("arp: ARP response read failed: %s", strerror(errno));
|
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_COLLISION_CHECK: arp_failed(cs); break;
|
||||||
case AS_GW_CHECK: arp_gw_failed(cs); break;
|
case AS_GW_CHECK: arp_gw_failed(cs); break;
|
||||||
default: arp_reopen_fd(cs); break;
|
default: arp_reopen_fd(cs); break;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
arpreply_offset += (size_t)r;
|
garp.reply_offset += (size_t)r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r <= 0) {
|
if (r <= 0) {
|
||||||
@ -729,37 +744,38 @@ void handle_arp_response(struct client_state_t *cs)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arpreply_offset < ARP_MSG_SIZE)
|
if (garp.reply_offset < ARP_MSG_SIZE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Emulate the BPF filters if they are not in use.
|
// Emulate the BPF filters if they are not in use.
|
||||||
if (!using_arp_bpf && (!arp_validate_bpf(&arpreply) ||
|
if (!garp.using_bpf &&
|
||||||
(arpState == AS_DEFENSE &&
|
(!arp_validate_bpf(&garp.reply) ||
|
||||||
!arp_validate_bpf_defense(cs, &arpreply)))) {
|
(garp.state == AS_DEFENSE &&
|
||||||
arpreply_clear();
|
!arp_validate_bpf_defense(cs, &garp.reply)))) {
|
||||||
|
arp_reply_clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arp_states[arpState].packet_fn)
|
if (arp_states[garp.state].packet_fn)
|
||||||
arp_states[arpState].packet_fn(cs);
|
arp_states[garp.state].packet_fn(cs);
|
||||||
arpreply_clear();
|
arp_reply_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform retransmission if necessary.
|
// Perform retransmission if necessary.
|
||||||
void handle_arp_timeout(struct client_state_t *cs, long long nowts)
|
void handle_arp_timeout(struct client_state_t *cs, long long nowts)
|
||||||
{
|
{
|
||||||
if (arp_states[arpState].timeout_fn)
|
if (arp_states[garp.state].timeout_fn)
|
||||||
arp_states[arpState].timeout_fn(cs, nowts);
|
arp_states[garp.state].timeout_fn(cs, nowts);
|
||||||
}
|
}
|
||||||
|
|
||||||
long long arp_get_wake_ts(void)
|
long long arp_get_wake_ts(void)
|
||||||
{
|
{
|
||||||
long long mt = -1;
|
long long mt = -1;
|
||||||
for (int i = 0; i < AS_MAX; ++i) {
|
for (int i = 0; i < AS_MAX; ++i) {
|
||||||
if (arp_wake_ts[i] < 0)
|
if (garp.wake_ts[i] < 0)
|
||||||
continue;
|
continue;
|
||||||
if (mt < 0 || mt > arp_wake_ts[i])
|
if (mt < 0 || mt > garp.wake_ts[i])
|
||||||
mt = arp_wake_ts[i];
|
mt = garp.wake_ts[i];
|
||||||
}
|
}
|
||||||
return mt;
|
return mt;
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,8 @@ extern int arp_probe_wait;
|
|||||||
extern int arp_probe_num;
|
extern int arp_probe_num;
|
||||||
extern int arp_probe_min;
|
extern int arp_probe_min;
|
||||||
extern int arp_probe_max;
|
extern int arp_probe_max;
|
||||||
extern int arp_relentless_def;
|
|
||||||
|
|
||||||
|
void set_arp_relentless_def(void);
|
||||||
void arp_reset_send_stats(void);
|
void arp_reset_send_stats(void);
|
||||||
void arp_close_fd(struct client_state_t *cs);
|
void arp_close_fd(struct client_state_t *cs);
|
||||||
int arp_check(struct client_state_t *cs, struct dhcpmsg *packet);
|
int arp_check(struct client_state_t *cs, struct dhcpmsg *packet);
|
||||||
|
@ -538,7 +538,7 @@ static void parse_program_options(int argc, char *argv[])
|
|||||||
seccomp_enforce = true;
|
seccomp_enforce = true;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
arp_relentless_def = 1;
|
set_arp_relentless_def();
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
case 'W': {
|
case 'W': {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user