2011-03-31 08:47:27 +05:30
|
|
|
/* arp.c - arp ping checking
|
2011-03-31 09:29:22 +05:30
|
|
|
*
|
2017-01-12 17:00:44 +05:30
|
|
|
* Copyright (c) 2010-2017 Nicholas J. Kain <njkain at gmail dot com>
|
2011-07-25 12:00:57 +05:30
|
|
|
* All rights reserved.
|
2011-03-31 08:47:27 +05:30
|
|
|
*
|
2011-07-25 12:00:57 +05:30
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
2011-03-31 09:29:22 +05:30
|
|
|
*
|
2011-07-25 12:00:57 +05:30
|
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
2011-03-31 09:29:22 +05:30
|
|
|
*
|
2011-07-25 12:00:57 +05:30
|
|
|
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
|
* and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
2010-11-16 06:36:50 +05:30
|
|
|
*/
|
2014-04-06 07:09:27 +05:30
|
|
|
#include <stdbool.h>
|
2010-11-16 06:36:50 +05:30
|
|
|
#include <unistd.h>
|
2010-12-24 20:02:58 +05:30
|
|
|
#include <stdlib.h>
|
2010-11-16 06:36:50 +05:30
|
|
|
#include <string.h>
|
2011-07-11 20:09:36 +05:30
|
|
|
#include <limits.h>
|
2010-11-16 06:36:50 +05:30
|
|
|
#include <netinet/if_ether.h>
|
2010-12-24 20:02:58 +05:30
|
|
|
#include <arpa/inet.h>
|
2011-06-25 22:32:56 +05:30
|
|
|
#include <linux/if_packet.h>
|
2011-07-01 10:25:35 +05:30
|
|
|
#include <linux/filter.h>
|
2010-11-16 06:36:50 +05:30
|
|
|
#include <errno.h>
|
2014-03-31 02:32:48 +05:30
|
|
|
#include "nk/log.h"
|
|
|
|
#include "nk/io.h"
|
2010-12-24 20:28:47 +05:30
|
|
|
#include "arp.h"
|
2011-06-30 09:17:31 +05:30
|
|
|
#include "state.h"
|
2011-07-02 13:21:44 +05:30
|
|
|
#include "dhcp.h"
|
2010-12-24 20:02:58 +05:30
|
|
|
#include "sys.h"
|
2010-12-24 20:42:41 +05:30
|
|
|
#include "ifchange.h"
|
2011-07-05 05:37:16 +05:30
|
|
|
#include "options.h"
|
2011-04-20 02:07:43 +05:30
|
|
|
#include "leasefile.h"
|
2014-04-04 13:42:25 +05:30
|
|
|
#include "sockd.h"
|
2015-02-14 15:50:04 +05:30
|
|
|
#include "netlink.h"
|
2010-11-16 06:36:50 +05:30
|
|
|
|
2011-03-31 12:02:34 +05:30
|
|
|
#define ARP_MSG_SIZE 0x2a
|
2011-07-05 05:37:16 +05:30
|
|
|
#define ARP_RETRANS_DELAY 5000 // ms
|
|
|
|
|
2011-07-05 22:33:55 +05:30
|
|
|
// From RFC5227
|
2013-02-09 11:00:19 +05:30
|
|
|
int arp_probe_wait = 1000; // initial random delay (ms)
|
|
|
|
int arp_probe_num = 3; // number of probe packets
|
|
|
|
int arp_probe_min = 1000; // minimum delay until repeated probe (ms)
|
|
|
|
int arp_probe_max = 2000; // maximum delay until repeated probe (ms)
|
2011-07-05 22:33:55 +05:30
|
|
|
#define ANNOUNCE_WAIT 2000 // delay before announcing
|
|
|
|
#define ANNOUNCE_NUM 2 // number of Announcement packets
|
|
|
|
#define ANNOUNCE_INTERVAL 2000 // time between Announcement packets
|
|
|
|
#define MAX_CONFLICTS 10 // max conflicts before rate-limiting
|
|
|
|
#define RATE_LIMIT_INTERVAL 60000 // delay between successive attempts
|
|
|
|
#define DEFEND_INTERVAL 10000 // minimum interval between defensive ARPs
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
static struct arp_data garp = {
|
2014-04-07 07:42:31 +05:30
|
|
|
.wake_ts = { -1, -1, -1, -1, -1 },
|
2015-02-14 09:55:42 +05:30
|
|
|
.send_stats = {{0,0},{0,0},{0,0}},
|
2014-04-07 07:42:31 +05:30
|
|
|
.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,
|
|
|
|
};
|
2011-07-06 18:56:07 +05:30
|
|
|
|
2014-04-15 00:36:31 +05:30
|
|
|
void set_arp_relentless_def(bool v) { garp.relentless_def = v; }
|
2011-07-11 22:54:59 +05:30
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
void arp_reply_clear(void)
|
2011-07-06 18:56:07 +05:30
|
|
|
{
|
2014-04-07 07:42:31 +05:30
|
|
|
memset(&garp.reply, 0, sizeof garp.reply);
|
|
|
|
garp.reply_offset = 0;
|
2011-07-06 18:56:07 +05:30
|
|
|
}
|
2011-03-31 12:02:34 +05:30
|
|
|
|
2011-07-06 01:10:57 +05:30
|
|
|
void arp_reset_send_stats(void)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < ASEND_MAX; ++i) {
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.send_stats[i].ts = 0;
|
|
|
|
garp.send_stats[i].count = 0;
|
2011-07-06 01:10:57 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
static int get_arp_basic_socket(struct client_state_t cs[static 1])
|
2010-11-16 06:36:50 +05:30
|
|
|
{
|
2014-04-06 07:09:27 +05:30
|
|
|
char resp;
|
|
|
|
int fd = request_sockd_fd("a", 1, &resp);
|
|
|
|
switch (resp) {
|
2014-04-07 07:42:31 +05:30
|
|
|
case 'A': garp.using_bpf = true; break;
|
|
|
|
case 'a': garp.using_bpf = false; break;
|
2014-04-06 07:09:27 +05:30
|
|
|
default: suicide("%s: (%s) expected a or A sockd reply but got %c",
|
|
|
|
client_config.interface, __func__, resp);
|
|
|
|
}
|
2015-02-18 16:01:13 +05:30
|
|
|
cs->arp_is_defense = false;
|
2014-04-06 07:09:27 +05:30
|
|
|
return fd;
|
2011-07-05 05:37:16 +05:30
|
|
|
}
|
2011-07-01 10:25:35 +05:30
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
static int get_arp_defense_socket(struct client_state_t cs[static 1])
|
2014-04-04 13:42:25 +05:30
|
|
|
{
|
2014-04-06 07:09:27 +05:30
|
|
|
char buf[32];
|
|
|
|
size_t buflen = 0;
|
|
|
|
buf[0] = 'd';
|
|
|
|
buflen += 1;
|
|
|
|
memcpy(buf + buflen, &cs->clientAddr, sizeof cs->clientAddr);
|
|
|
|
buflen += sizeof cs->clientAddr;
|
|
|
|
memcpy(buf + buflen, client_config.arp, 6);
|
|
|
|
buflen += 6;
|
|
|
|
char resp;
|
|
|
|
int fd = request_sockd_fd(buf, buflen, &resp);
|
|
|
|
switch (resp) {
|
2014-04-07 07:42:31 +05:30
|
|
|
case 'D': garp.using_bpf = true; break;
|
|
|
|
case 'd': garp.using_bpf = false; break;
|
2014-04-06 07:09:27 +05:30
|
|
|
default: suicide("%s: (%s) expected d or D sockd reply but got %c",
|
|
|
|
client_config.interface, __func__, resp);
|
|
|
|
}
|
2015-02-18 16:01:13 +05:30
|
|
|
cs->arp_is_defense = true;
|
2014-04-06 07:09:27 +05:30
|
|
|
return fd;
|
2014-04-04 13:42:25 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
static void arp_min_close_fd(struct client_state_t cs[static 1])
|
2014-04-06 07:09:27 +05:30
|
|
|
{
|
2014-04-06 15:24:21 +05:30
|
|
|
if (cs->arpFd < 0)
|
2014-04-06 09:10:18 +05:30
|
|
|
return;
|
2014-04-06 07:09:27 +05:30
|
|
|
epoll_del(cs->epollFd, cs->arpFd);
|
|
|
|
close(cs->arpFd);
|
|
|
|
cs->arpFd = -1;
|
2015-02-18 16:01:13 +05:30
|
|
|
cs->arp_is_defense = false;
|
2011-06-25 22:32:56 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
void arp_close_fd(struct client_state_t cs[static 1])
|
2011-07-11 20:09:36 +05:30
|
|
|
{
|
|
|
|
arp_min_close_fd(cs);
|
|
|
|
for (int i = 0; i < AS_MAX; ++i)
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[i] = -1;
|
2011-07-11 20:09:36 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
static int arp_open_fd(struct client_state_t cs[static 1], bool defense)
|
2011-07-05 08:05:53 +05:30
|
|
|
{
|
2015-02-18 16:01:13 +05:30
|
|
|
if (cs->arpFd >= 0 && defense == cs->arp_is_defense)
|
|
|
|
return 0;
|
2011-07-11 20:09:36 +05:30
|
|
|
arp_min_close_fd(cs);
|
2015-02-18 16:01:13 +05:30
|
|
|
cs->arpFd = defense ? get_arp_defense_socket(cs)
|
|
|
|
: get_arp_basic_socket(cs);
|
|
|
|
if (cs->arpFd < 0) {
|
|
|
|
log_error("%s: (%s) Failed to create socket: %s",
|
|
|
|
client_config.interface, __func__, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
epoll_add(cs->epollFd, cs->arpFd);
|
|
|
|
arp_reply_clear();
|
|
|
|
return 0;
|
2011-07-05 08:05:53 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 09:44:08 +05:30
|
|
|
static int arp_send(struct client_state_t cs[static 1],
|
|
|
|
struct arpMsg arp[static 1])
|
2011-06-25 22:32:56 +05:30
|
|
|
{
|
2015-02-14 15:50:04 +05:30
|
|
|
int ret = -1;
|
2011-07-05 05:37:16 +05:30
|
|
|
struct sockaddr_ll addr = {
|
|
|
|
.sll_family = AF_PACKET,
|
|
|
|
.sll_ifindex = client_config.ifindex,
|
|
|
|
.sll_halen = 6,
|
|
|
|
};
|
|
|
|
memcpy(addr.sll_addr, client_config.arp, 6);
|
|
|
|
|
2014-04-06 15:24:21 +05:30
|
|
|
if (cs->arpFd < 0) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: Send attempted when no ARP fd is open.",
|
|
|
|
client_config.interface);
|
2015-02-14 15:50:04 +05:30
|
|
|
return ret;
|
2011-07-05 08:05:53 +05:30
|
|
|
}
|
|
|
|
|
2017-01-12 15:55:15 +05:30
|
|
|
if (!carrier_isup()) {
|
2015-02-14 08:23:15 +05:30
|
|
|
log_error("%s: (%s) carrier down; sendto would fail",
|
|
|
|
client_config.interface, __func__);
|
2015-02-14 15:50:04 +05:30
|
|
|
ret = -99;
|
2015-02-14 08:23:15 +05:30
|
|
|
goto carrier_down;
|
|
|
|
}
|
2015-02-14 15:50:04 +05:30
|
|
|
ret = safe_sendto(cs->arpFd, (const char *)arp, sizeof *arp, 0,
|
2015-02-14 08:23:15 +05:30
|
|
|
(struct sockaddr *)&addr, sizeof addr);
|
2015-02-14 15:50:04 +05:30
|
|
|
if (ret < 0 || (size_t)ret != sizeof *arp) {
|
|
|
|
if (ret < 0)
|
2014-04-07 14:13:21 +05:30
|
|
|
log_error("%s: (%s) sendto failed: %s",
|
|
|
|
client_config.interface, __func__, strerror(errno));
|
2014-04-07 13:45:02 +05:30
|
|
|
else
|
2015-02-14 15:50:04 +05:30
|
|
|
log_error("%s: (%s) sendto short write: %d < %zu",
|
|
|
|
client_config.interface, __func__, ret, sizeof *arp);
|
2015-02-14 08:23:15 +05:30
|
|
|
carrier_down:
|
2015-02-14 15:50:04 +05:30
|
|
|
return ret;
|
2011-07-05 05:37:16 +05:30
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2011-06-25 22:32:56 +05:30
|
|
|
|
2011-07-05 05:49:30 +05:30
|
|
|
#define BASE_ARPMSG() struct arpMsg arp = { \
|
|
|
|
.h_proto = htons(ETH_P_ARP), \
|
|
|
|
.htype = htons(ARPHRD_ETHER), \
|
|
|
|
.ptype = htons(ETH_P_IP), \
|
|
|
|
.hlen = 6, .plen = 4, \
|
2014-03-11 04:55:06 +05:30
|
|
|
.operation = htons(ARPOP_REQUEST), \
|
|
|
|
.smac = {0}, \
|
|
|
|
}; \
|
2011-07-05 05:49:30 +05:30
|
|
|
memcpy(arp.h_source, client_config.arp, 6); \
|
|
|
|
memset(arp.h_dest, 0xff, 6); \
|
|
|
|
memcpy(arp.smac, client_config.arp, 6)
|
|
|
|
|
2011-07-05 05:37:16 +05:30
|
|
|
// Returns 0 on success, -1 on failure.
|
2015-02-14 08:59:03 +05:30
|
|
|
static int arp_ping(struct client_state_t cs[static 1], uint32_t test_ip)
|
2011-07-05 05:37:16 +05:30
|
|
|
{
|
2011-07-05 05:49:30 +05:30
|
|
|
BASE_ARPMSG();
|
2011-07-05 05:37:16 +05:30
|
|
|
memcpy(arp.sip4, &cs->clientAddr, sizeof cs->clientAddr);
|
2011-07-05 05:49:30 +05:30
|
|
|
memcpy(arp.dip4, &test_ip, sizeof test_ip);
|
2015-02-14 15:50:04 +05:30
|
|
|
int r = arp_send(cs, &arp);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.send_stats[ASEND_GW_PING].count++;
|
|
|
|
garp.send_stats[ASEND_GW_PING].ts = curms();
|
2011-07-06 01:10:57 +05:30
|
|
|
return 0;
|
2011-07-05 05:37:16 +05:30
|
|
|
}
|
2011-06-25 22:32:56 +05:30
|
|
|
|
2011-07-05 05:37:16 +05:30
|
|
|
// Returns 0 on success, -1 on failure.
|
2015-02-14 09:44:08 +05:30
|
|
|
static int arp_ip_anon_ping(struct client_state_t cs[static 1],
|
|
|
|
uint32_t test_ip)
|
2011-07-05 05:37:16 +05:30
|
|
|
{
|
2011-07-05 05:49:30 +05:30
|
|
|
BASE_ARPMSG();
|
2011-07-05 05:37:16 +05:30
|
|
|
memcpy(arp.dip4, &test_ip, sizeof test_ip);
|
2014-04-07 14:13:21 +05:30
|
|
|
log_line("%s: arp: Probing for hosts that may conflict with our lease...",
|
|
|
|
client_config.interface);
|
2015-02-14 15:50:04 +05:30
|
|
|
int r = arp_send(cs, &arp);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.send_stats[ASEND_COLLISION_CHECK].count++;
|
|
|
|
garp.send_stats[ASEND_COLLISION_CHECK].ts = curms();
|
2011-07-06 01:10:57 +05:30
|
|
|
return 0;
|
2010-11-16 06:36:50 +05:30
|
|
|
}
|
2010-12-24 20:02:58 +05:30
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
static int arp_announcement(struct client_state_t cs[static 1])
|
2011-07-02 15:18:24 +05:30
|
|
|
{
|
2011-07-05 05:49:30 +05:30
|
|
|
BASE_ARPMSG();
|
2011-07-02 15:18:24 +05:30
|
|
|
memcpy(arp.sip4, &cs->clientAddr, 4);
|
|
|
|
memcpy(arp.dip4, &cs->clientAddr, 4);
|
2015-02-14 15:50:04 +05:30
|
|
|
int r = arp_send(cs, &arp);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.send_stats[ASEND_ANNOUNCE].count++;
|
|
|
|
garp.send_stats[ASEND_ANNOUNCE].ts = curms();
|
2011-07-06 01:10:57 +05:30
|
|
|
return 0;
|
2011-07-02 15:18:24 +05:30
|
|
|
}
|
2011-07-05 05:49:30 +05:30
|
|
|
#undef BASE_ARPMSG
|
2011-07-02 15:18:24 +05:30
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
// Checks to see if there is another host that has our assigned IP.
|
2015-02-14 09:44:08 +05:30
|
|
|
int arp_check(struct client_state_t cs[static 1],
|
|
|
|
struct dhcpmsg packet[static 1])
|
2010-12-24 20:02:58 +05:30
|
|
|
{
|
2014-04-07 07:42:31 +05:30
|
|
|
memcpy(&garp.dhcp_packet, packet, sizeof (struct dhcpmsg));
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_open_fd(cs, false) < 0)
|
|
|
|
return -1;
|
2014-04-07 07:42:31 +05:30
|
|
|
if (arp_ip_anon_ping(cs, garp.dhcp_packet.yiaddr) < 0)
|
2011-03-31 12:02:34 +05:30
|
|
|
return -1;
|
2014-04-07 07:42:31 +05:30
|
|
|
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;
|
2011-03-31 12:02:34 +05:30
|
|
|
return 0;
|
2010-12-24 20:02:58 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
// Confirms that we're still on the fingerprinted network.
|
2015-02-14 08:59:03 +05:30
|
|
|
int arp_gw_check(struct client_state_t cs[static 1])
|
2011-03-31 05:43:48 +05:30
|
|
|
{
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_open_fd(cs, false) < 0)
|
|
|
|
return -1;
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.gw_check_initpings = garp.send_stats[ASEND_GW_PING].count;
|
|
|
|
garp.server_replied = false;
|
2015-02-18 16:01:13 +05:30
|
|
|
cs->check_fingerprint = true;
|
2015-02-14 16:07:06 +05:30
|
|
|
int r;
|
|
|
|
if ((r = arp_ping(cs, cs->srcAddr)) < 0)
|
|
|
|
return r;
|
2011-07-11 22:54:59 +05:30
|
|
|
if (cs->routerAddr) {
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.router_replied = false;
|
2015-02-14 16:07:06 +05:30
|
|
|
if ((r = arp_ping(cs, cs->routerAddr)) < 0)
|
|
|
|
return r;
|
2011-07-11 22:54:59 +05:30
|
|
|
} else
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.router_replied = true;
|
|
|
|
garp.wake_ts[AS_GW_CHECK] =
|
|
|
|
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
|
2011-03-31 12:02:34 +05:30
|
|
|
return 0;
|
2011-03-31 05:43:48 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
// Gathers the fingerprinting info for the associated network.
|
2015-02-14 08:59:03 +05:30
|
|
|
static int arp_get_gw_hwaddr(struct client_state_t cs[static 1])
|
2011-03-31 08:47:27 +05:30
|
|
|
{
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_open_fd(cs, false) < 0)
|
|
|
|
return -1;
|
2011-07-11 22:54:59 +05:30
|
|
|
if (cs->routerAddr)
|
2014-04-07 14:13:21 +05:30
|
|
|
log_line("%s: arp: Searching for dhcp server and gw addresses...",
|
|
|
|
client_config.interface);
|
2011-07-11 22:54:59 +05:30
|
|
|
else
|
2014-04-07 14:13:21 +05:30
|
|
|
log_line("%s: arp: Searching for dhcp server address...",
|
|
|
|
client_config.interface);
|
2017-01-19 15:31:23 +05:30
|
|
|
cs->got_server_arp = false;
|
2015-02-13 09:58:54 +05:30
|
|
|
if (arp_ping(cs, cs->srcAddr) < 0)
|
2011-03-31 12:02:34 +05:30
|
|
|
return -1;
|
2011-07-11 22:54:59 +05:30
|
|
|
if (cs->routerAddr) {
|
2017-01-19 15:31:23 +05:30
|
|
|
cs->got_router_arp = false;
|
2014-04-06 15:24:21 +05:30
|
|
|
if (arp_ping(cs, cs->routerAddr) < 0)
|
2011-07-11 22:54:59 +05:30
|
|
|
return -1;
|
|
|
|
} else
|
2017-01-19 15:31:23 +05:30
|
|
|
cs->got_router_arp = true;
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_GW_QUERY] =
|
|
|
|
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY + 250;
|
2011-03-31 12:02:34 +05:30
|
|
|
return 0;
|
2011-03-31 08:47:27 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
int arp_set_defense_mode(struct client_state_t cs[static 1])
|
2011-07-06 01:27:11 +05:30
|
|
|
{
|
2015-02-18 16:01:13 +05:30
|
|
|
return arp_open_fd(cs, true);
|
2010-12-24 20:02:58 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
static int arp_gw_success(struct client_state_t cs[static 1])
|
2011-03-31 05:43:48 +05:30
|
|
|
{
|
2014-04-07 14:13:21 +05:30
|
|
|
log_line("%s: arp: Network seems unchanged. Resuming normal operation.",
|
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_open_fd(cs, true) < 0)
|
|
|
|
return ARPR_FAIL;
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_GW_CHECK] = -1;
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_announcement(cs) < 0)
|
|
|
|
return ARPR_FAIL;
|
|
|
|
return ARPR_FREE;
|
2011-03-31 05:43:48 +05:30
|
|
|
}
|
|
|
|
|
2011-07-01 12:31:29 +05:30
|
|
|
// ARP validation functions that will be performed by the BPF if it is
|
|
|
|
// installed.
|
|
|
|
static int arp_validate_bpf(struct arpMsg *am)
|
2011-05-31 20:31:08 +05:30
|
|
|
{
|
2011-06-02 20:11:34 +05:30
|
|
|
if (am->h_proto != htons(ETH_P_ARP)) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: IP header does not indicate ARP protocol",
|
|
|
|
client_config.interface);
|
2011-05-31 20:31:08 +05:30
|
|
|
return 0;
|
2011-06-02 20:11:34 +05:30
|
|
|
}
|
|
|
|
if (am->htype != htons(ARPHRD_ETHER)) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: ARP hardware type field invalid",
|
|
|
|
client_config.interface);
|
2011-05-31 20:31:08 +05:30
|
|
|
return 0;
|
2011-06-02 20:11:34 +05:30
|
|
|
}
|
|
|
|
if (am->ptype != htons(ETH_P_IP)) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: ARP protocol type field invalid",
|
|
|
|
client_config.interface);
|
2011-05-31 20:31:08 +05:30
|
|
|
return 0;
|
2011-06-02 20:11:34 +05:30
|
|
|
}
|
|
|
|
if (am->hlen != 6) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: ARP hardware address length invalid",
|
|
|
|
client_config.interface);
|
2011-05-31 20:31:08 +05:30
|
|
|
return 0;
|
2011-06-02 20:11:34 +05:30
|
|
|
}
|
|
|
|
if (am->plen != 4) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: ARP protocol address length invalid",
|
|
|
|
client_config.interface);
|
2011-05-31 20:31:08 +05:30
|
|
|
return 0;
|
2011-06-02 20:11:34 +05:30
|
|
|
}
|
2011-07-01 12:31:29 +05:30
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-07-05 05:37:16 +05:30
|
|
|
// ARP validation functions that will be performed by the BPF if it is
|
|
|
|
// installed.
|
2015-02-14 08:59:03 +05:30
|
|
|
static int arp_validate_bpf_defense(struct client_state_t cs[static 1],
|
2015-02-14 09:44:08 +05:30
|
|
|
struct arpMsg am[static 1])
|
2011-07-01 12:31:29 +05:30
|
|
|
{
|
2011-07-05 05:37:16 +05:30
|
|
|
if (memcmp(am->sip4, &cs->clientAddr, 4))
|
|
|
|
return 0;
|
|
|
|
if (!memcmp(am->smac, client_config.arp, 6))
|
2011-05-31 20:31:08 +05:30
|
|
|
return 0;
|
2011-07-05 05:37:16 +05:30
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-02-14 09:44:08 +05:30
|
|
|
static int arp_is_query_reply(struct arpMsg am[static 1])
|
2011-07-05 05:37:16 +05:30
|
|
|
{
|
2011-07-01 12:31:29 +05:30
|
|
|
if (am->operation != htons(ARPOP_REPLY))
|
2011-05-31 20:31:08 +05:30
|
|
|
return 0;
|
2011-07-01 12:31:29 +05:30
|
|
|
if (memcmp(am->h_dest, client_config.arp, 6))
|
|
|
|
return 0;
|
|
|
|
if (memcmp(am->dmac, client_config.arp, 6))
|
2011-05-31 20:31:08 +05:30
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
static int arp_gen_probe_wait(struct client_state_t cs[static 1])
|
2011-07-06 01:10:57 +05:30
|
|
|
{
|
|
|
|
// This is not a uniform distribution but it doesn't matter here.
|
2014-03-22 11:38:23 +05:30
|
|
|
return arp_probe_min + (nk_random_u32(&cs->rnd32_state) & 0x7fffffffu)
|
|
|
|
% (arp_probe_max - arp_probe_min);
|
2011-07-06 01:10:57 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
int arp_defense_timeout(struct client_state_t cs[static 1], long long nowts)
|
2011-07-05 20:37:42 +05:30
|
|
|
{
|
2014-03-11 04:55:06 +05:30
|
|
|
(void)nowts; // Suppress warning; parameter necessary but unused.
|
2015-02-18 16:01:13 +05:30
|
|
|
int ret = 0;
|
2014-04-07 07:42:31 +05:30
|
|
|
if (garp.wake_ts[AS_DEFENSE] != -1) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_line("%s: arp: Defending our lease IP.", client_config.interface);
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_DEFENSE] = -1;
|
2015-02-18 16:01:13 +05:30
|
|
|
ret = arp_announcement(cs);
|
2011-07-05 22:33:55 +05:30
|
|
|
}
|
2015-02-18 16:01:13 +05:30
|
|
|
return ret;
|
2011-07-11 14:39:38 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
int arp_gw_check_timeout(struct client_state_t cs[static 1], long long nowts)
|
2011-07-11 14:39:38 +05:30
|
|
|
{
|
2015-02-18 16:01:13 +05:30
|
|
|
if (garp.send_stats[ASEND_GW_PING].count >= garp.gw_check_initpings + 6) {
|
|
|
|
if (garp.router_replied && !garp.server_replied)
|
|
|
|
log_line("%s: arp: DHCP agent didn't reply. Getting new lease.",
|
|
|
|
client_config.interface);
|
|
|
|
else if (!garp.router_replied && garp.server_replied)
|
|
|
|
log_line("%s: arp: Gateway didn't reply. Getting new lease.",
|
|
|
|
client_config.interface);
|
|
|
|
else
|
|
|
|
log_line("%s: arp: DHCP agent and gateway didn't reply. Getting new lease.",
|
|
|
|
client_config.interface);
|
|
|
|
garp.wake_ts[AS_GW_CHECK] = -1;
|
|
|
|
return ARPR_CONFLICT;
|
|
|
|
}
|
2014-04-07 07:42:31 +05:30
|
|
|
long long rtts = garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
|
2011-07-11 18:29:50 +05:30
|
|
|
if (nowts < rtts) {
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_GW_CHECK] = rtts;
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-06 01:10:57 +05:30
|
|
|
}
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!garp.router_replied) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_line("%s: arp: Still waiting for gateway to reply to arp ping...",
|
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_ping(cs, cs->routerAddr) < 0) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: Failed to send ARP ping in retransmission.",
|
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_FAIL;
|
|
|
|
}
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!garp.server_replied) {
|
2015-02-13 09:58:54 +05:30
|
|
|
log_line("%s: arp: Still waiting for DHCP agent to reply to arp ping...",
|
2014-04-07 14:13:21 +05:30
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_ping(cs, cs->srcAddr) < 0) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: Failed to send ARP ping in retransmission.",
|
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_FAIL;
|
|
|
|
}
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_GW_CHECK] =
|
|
|
|
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
int arp_gw_query_timeout(struct client_state_t cs[static 1], long long nowts)
|
2015-02-13 07:19:40 +05:30
|
|
|
{
|
2014-04-07 07:42:31 +05:30
|
|
|
long long rtts = garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
|
2011-07-11 22:54:59 +05:30
|
|
|
if (nowts < rtts) {
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_GW_QUERY] = rtts;
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
|
|
|
if (!cs->got_router_arp) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_line("%s: arp: Still looking for gateway hardware address...",
|
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_ping(cs, cs->routerAddr) < 0) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: Failed to send ARP ping in retransmission.",
|
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_FAIL;
|
|
|
|
}
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
|
|
|
if (!cs->got_server_arp) {
|
2015-02-13 09:58:54 +05:30
|
|
|
log_line("%s: arp: Still looking for DHCP agent hardware address...",
|
2014-04-07 14:13:21 +05:30
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_ping(cs, cs->srcAddr) < 0) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: Failed to send ARP ping in retransmission.",
|
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_FAIL;
|
|
|
|
}
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_GW_QUERY] =
|
|
|
|
garp.send_stats[ASEND_GW_PING].ts + ARP_RETRANS_DELAY;
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-11 14:39:38 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
int arp_collision_timeout(struct client_state_t cs[static 1], long long nowts)
|
2011-07-11 14:39:38 +05:30
|
|
|
{
|
2014-04-07 07:42:31 +05:30
|
|
|
if (nowts >= garp.arp_check_start_ts + ANNOUNCE_WAIT ||
|
2015-02-18 16:01:13 +05:30
|
|
|
garp.send_stats[ASEND_COLLISION_CHECK].count >= arp_probe_num)
|
|
|
|
{
|
|
|
|
char clibuf[INET_ADDRSTRLEN];
|
|
|
|
struct in_addr temp_addr = {.s_addr = garp.dhcp_packet.yiaddr};
|
|
|
|
inet_ntop(AF_INET, &temp_addr, clibuf, sizeof clibuf);
|
|
|
|
log_line("%s: Lease of %s obtained. Lease time is %ld seconds.",
|
|
|
|
client_config.interface, clibuf, cs->lease);
|
|
|
|
cs->clientAddr = garp.dhcp_packet.yiaddr;
|
2017-01-19 15:31:23 +05:30
|
|
|
cs->init = false;
|
2015-02-18 16:01:13 +05:30
|
|
|
garp.last_conflict_ts = 0;
|
|
|
|
garp.wake_ts[AS_COLLISION_CHECK] = -1;
|
|
|
|
if (ifchange_bind(cs, &garp.dhcp_packet) < 0) {
|
2015-10-29 05:50:21 +05:30
|
|
|
suicide("%s: Failed to set the interface IP address and properties!",
|
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
}
|
|
|
|
cs->routerAddr = get_option_router(&garp.dhcp_packet);
|
|
|
|
if (arp_get_gw_hwaddr(cs) < 0) {
|
|
|
|
log_warning("%s: (%s) Failed to send request to get gateway and agent hardware addresses: %s",
|
|
|
|
client_config.interface, __func__, strerror(errno));
|
|
|
|
return ARPR_FAIL;
|
|
|
|
}
|
|
|
|
stop_dhcp_listen(cs);
|
|
|
|
write_leasefile(temp_addr);
|
|
|
|
int ret = ARPR_FREE;
|
|
|
|
if (arp_announcement(cs) < 0)
|
|
|
|
ret = ARPR_FAIL;
|
|
|
|
if (client_config.quit_after_lease)
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
if (!client_config.foreground)
|
|
|
|
background();
|
|
|
|
return ret;
|
2011-07-11 14:39:38 +05:30
|
|
|
}
|
2014-04-07 07:42:31 +05:30
|
|
|
long long rtts = garp.send_stats[ASEND_COLLISION_CHECK].ts +
|
|
|
|
garp.probe_wait_time;
|
2011-07-11 18:29:50 +05:30
|
|
|
if (nowts < rtts) {
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_COLLISION_CHECK] = rtts;
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-05 20:37:42 +05:30
|
|
|
}
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_ip_anon_ping(cs, garp.dhcp_packet.yiaddr) < 0) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: Failed to send ARP ping in retransmission.",
|
|
|
|
client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_FAIL;
|
|
|
|
}
|
2014-04-07 07:42:31 +05:30
|
|
|
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;
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-05 20:37:42 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
int arp_do_defense(struct client_state_t cs[static 1])
|
2011-07-05 22:33:55 +05:30
|
|
|
{
|
2011-07-11 22:54:59 +05:30
|
|
|
// 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.
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!arp_validate_bpf_defense(cs, &garp.reply))
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-11 22:54:59 +05:30
|
|
|
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: Detected a peer attempting to use our IP!", client_config.interface);
|
2011-07-11 20:09:36 +05:30
|
|
|
long long nowts = curms();
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_DEFENSE] = -1;
|
|
|
|
if (!garp.last_conflict_ts ||
|
|
|
|
nowts - garp.last_conflict_ts < DEFEND_INTERVAL) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: Defending our lease IP.", client_config.interface);
|
2015-02-18 16:01:13 +05:30
|
|
|
if (arp_announcement(cs) < 0)
|
|
|
|
return ARPR_FAIL;
|
2014-04-07 07:42:31 +05:30
|
|
|
} else if (!garp.relentless_def) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_warning("%s: arp: Conflicting peer is persistent. Requesting new lease.",
|
|
|
|
client_config.interface);
|
2011-07-05 22:33:55 +05:30
|
|
|
send_release(cs);
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_CONFLICT;
|
2011-07-05 22:33:55 +05:30
|
|
|
} else {
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.wake_ts[AS_DEFENSE] =
|
|
|
|
garp.send_stats[ASEND_ANNOUNCE].ts + DEFEND_INTERVAL;
|
2011-07-05 22:33:55 +05:30
|
|
|
}
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.total_conflicts++;
|
|
|
|
garp.last_conflict_ts = nowts;
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-05 22:33:55 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
int arp_do_gw_query(struct client_state_t cs[static 1])
|
2011-07-11 14:39:38 +05:30
|
|
|
{
|
2015-02-18 16:01:13 +05:30
|
|
|
if (!arp_is_query_reply(&garp.reply))
|
|
|
|
return ARPR_OK;
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!memcmp(garp.reply.sip4, &cs->routerAddr, 4)) {
|
|
|
|
memcpy(cs->routerArp, garp.reply.smac, 6);
|
2014-04-07 14:13:21 +05:30
|
|
|
log_line("%s: arp: Gateway hardware address %02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
client_config.interface, cs->routerArp[0], cs->routerArp[1],
|
2011-07-11 14:39:38 +05:30
|
|
|
cs->routerArp[2], cs->routerArp[3],
|
|
|
|
cs->routerArp[4], cs->routerArp[5]);
|
2017-01-19 15:31:23 +05:30
|
|
|
cs->got_router_arp = true;
|
2015-02-13 09:58:54 +05:30
|
|
|
if (cs->routerAddr == cs->srcAddr)
|
2011-07-11 22:54:59 +05:30
|
|
|
goto server_is_router;
|
2015-02-18 16:01:13 +05:30
|
|
|
if (cs->got_server_arp) {
|
|
|
|
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;
|
2011-07-11 14:39:38 +05:30
|
|
|
}
|
2015-02-13 09:58:54 +05:30
|
|
|
if (!memcmp(garp.reply.sip4, &cs->srcAddr, 4)) {
|
2011-07-11 22:54:59 +05:30
|
|
|
server_is_router:
|
2014-04-07 07:42:31 +05:30
|
|
|
memcpy(cs->serverArp, garp.reply.smac, 6);
|
2015-02-13 09:58:54 +05:30
|
|
|
log_line("%s: arp: DHCP agent hardware address %02x:%02x:%02x:%02x:%02x:%02x",
|
2014-04-07 14:13:21 +05:30
|
|
|
client_config.interface, cs->serverArp[0], cs->serverArp[1],
|
2011-07-11 22:54:59 +05:30
|
|
|
cs->serverArp[2], cs->serverArp[3],
|
|
|
|
cs->serverArp[4], cs->serverArp[5]);
|
2017-01-19 15:31:23 +05:30
|
|
|
cs->got_server_arp = true;
|
2015-02-18 16:01:13 +05:30
|
|
|
if (cs->got_router_arp) {
|
|
|
|
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;
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-11 14:39:38 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
int arp_do_collision_check(struct client_state_t cs[static 1])
|
2011-07-11 14:39:38 +05:30
|
|
|
{
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!arp_is_query_reply(&garp.reply))
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-11 14:39:38 +05:30
|
|
|
// 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.
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!memcmp(garp.reply.sip4, &garp.dhcp_packet.yiaddr, 4) &&
|
2015-02-18 16:01:13 +05:30
|
|
|
!memcmp(client_config.arp, garp.reply.smac, 6))
|
|
|
|
{
|
2014-04-07 07:42:31 +05:30
|
|
|
garp.total_conflicts++;
|
2015-02-18 16:01:13 +05:30
|
|
|
garp.wake_ts[AS_COLLISION_CHECK] = -1;
|
|
|
|
log_line("%s: arp: Offered address is in use. Declining.",
|
|
|
|
client_config.interface);
|
|
|
|
int r = send_decline(cs, garp.dhcp_packet.yiaddr);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning("%s: Failed to send a decline notice packet.",
|
|
|
|
client_config.interface);
|
|
|
|
return ARPR_FAIL;
|
|
|
|
}
|
|
|
|
return ARPR_CONFLICT;
|
2011-07-11 14:39:38 +05:30
|
|
|
}
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2011-07-11 14:39:38 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
int arp_do_gw_check(struct client_state_t cs[static 1])
|
2011-07-11 14:39:38 +05:30
|
|
|
{
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!arp_is_query_reply(&garp.reply))
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!memcmp(garp.reply.sip4, &cs->routerAddr, 4)) {
|
2011-07-11 14:39:38 +05:30
|
|
|
// Success only if the router/gw MAC matches stored value
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!memcmp(cs->routerArp, garp.reply.smac, 6)) {
|
|
|
|
garp.router_replied = true;
|
2015-02-13 09:58:54 +05:30
|
|
|
if (cs->routerAddr == cs->srcAddr)
|
2011-07-11 22:54:59 +05:30
|
|
|
goto server_is_router;
|
2014-04-07 07:42:31 +05:30
|
|
|
if (garp.server_replied)
|
2015-02-18 16:01:13 +05:30
|
|
|
return arp_gw_success(cs); // FREE or FAIL
|
|
|
|
return ARPR_OK;
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
2015-02-18 16:01:13 +05:30
|
|
|
log_line("%s: arp: Gateway is different. Getting a new lease.",
|
|
|
|
client_config.interface);
|
|
|
|
garp.wake_ts[AS_GW_CHECK] = -1;
|
|
|
|
return ARPR_CONFLICT;
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
2015-02-13 09:58:54 +05:30
|
|
|
if (!memcmp(garp.reply.sip4, &cs->srcAddr, 4)) {
|
2011-07-11 22:54:59 +05:30
|
|
|
server_is_router:
|
|
|
|
// Success only if the server MAC matches stored value
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!memcmp(cs->serverArp, garp.reply.smac, 6)) {
|
|
|
|
garp.server_replied = true;
|
|
|
|
if (garp.router_replied)
|
2015-02-18 16:01:13 +05:30
|
|
|
return arp_gw_success(cs); // FREE or FAIL
|
|
|
|
return ARPR_OK;
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
2015-02-18 16:01:13 +05:30
|
|
|
log_line("%s: arp: DHCP agent is different. Getting a new lease.",
|
|
|
|
client_config.interface);
|
|
|
|
garp.wake_ts[AS_GW_CHECK] = -1;
|
|
|
|
return ARPR_CONFLICT;
|
2011-07-11 14:39:38 +05:30
|
|
|
}
|
2015-02-18 16:01:13 +05:30
|
|
|
return ARPR_OK;
|
2015-02-15 17:08:03 +05:30
|
|
|
}
|
|
|
|
|
2015-02-18 21:32:13 +05:30
|
|
|
bool arp_packet_get(struct client_state_t cs[static 1])
|
2010-12-24 20:02:58 +05:30
|
|
|
{
|
2014-04-06 15:54:13 +05:30
|
|
|
ssize_t r = 0;
|
2014-04-07 07:42:31 +05:30
|
|
|
if (garp.reply_offset < sizeof garp.reply) {
|
|
|
|
r = safe_read(cs->arpFd, (char *)&garp.reply + garp.reply_offset,
|
|
|
|
sizeof garp.reply - garp.reply_offset);
|
2015-02-15 17:08:03 +05:30
|
|
|
if (r == 0)
|
2015-02-18 21:32:13 +05:30
|
|
|
return false;
|
2014-04-06 15:32:03 +05:30
|
|
|
if (r < 0) {
|
2014-04-07 14:13:21 +05:30
|
|
|
log_error("%s: (%s) ARP response read failed: %s",
|
|
|
|
client_config.interface, __func__, strerror(errno));
|
2015-02-18 16:01:13 +05:30
|
|
|
// Timeouts will trigger anyway without being forced.
|
|
|
|
arp_min_close_fd(cs);
|
|
|
|
if (arp_open_fd(cs, cs->arp_is_defense) < 0)
|
|
|
|
suicide("%s: (%s) Failed to reopen ARP fd: %s",
|
|
|
|
client_config.interface, __func__, strerror(errno));
|
2015-02-18 21:32:13 +05:30
|
|
|
return false;
|
2015-02-15 17:08:03 +05:30
|
|
|
}
|
|
|
|
garp.reply_offset += (size_t)r;
|
2011-07-05 05:37:16 +05:30
|
|
|
}
|
2011-06-29 09:20:36 +05:30
|
|
|
|
2014-04-07 07:42:31 +05:30
|
|
|
if (garp.reply_offset < ARP_MSG_SIZE)
|
2015-02-18 21:32:13 +05:30
|
|
|
return false;
|
2011-03-31 12:02:34 +05:30
|
|
|
|
2011-07-05 05:37:16 +05:30
|
|
|
// Emulate the BPF filters if they are not in use.
|
2014-04-07 07:42:31 +05:30
|
|
|
if (!garp.using_bpf &&
|
|
|
|
(!arp_validate_bpf(&garp.reply) ||
|
2015-02-18 16:01:13 +05:30
|
|
|
(cs->arp_is_defense &&
|
2014-04-07 07:42:31 +05:30
|
|
|
!arp_validate_bpf_defense(cs, &garp.reply)))) {
|
|
|
|
arp_reply_clear();
|
2015-02-18 21:32:13 +05:30
|
|
|
return false;
|
2011-06-29 09:20:36 +05:30
|
|
|
}
|
2015-02-18 21:32:13 +05:30
|
|
|
return true;
|
2011-07-11 14:39:38 +05:30
|
|
|
}
|
2011-07-11 20:09:36 +05:30
|
|
|
|
2015-02-18 16:01:13 +05:30
|
|
|
// XXX: Move into client_state
|
2011-07-11 21:01:27 +05:30
|
|
|
long long arp_get_wake_ts(void)
|
2011-07-11 20:09:36 +05:30
|
|
|
{
|
2011-07-11 21:01:27 +05:30
|
|
|
long long mt = -1;
|
2011-07-11 20:09:36 +05:30
|
|
|
for (int i = 0; i < AS_MAX; ++i) {
|
2014-04-07 07:42:31 +05:30
|
|
|
if (garp.wake_ts[i] < 0)
|
2011-07-11 20:09:36 +05:30
|
|
|
continue;
|
2014-04-07 07:42:31 +05:30
|
|
|
if (mt < 0 || mt > garp.wake_ts[i])
|
|
|
|
mt = garp.wake_ts[i];
|
2011-07-11 20:09:36 +05:30
|
|
|
}
|
2011-07-11 21:01:27 +05:30
|
|
|
return mt;
|
2011-07-11 20:09:36 +05:30
|
|
|
}
|
|
|
|
|