Check the server identifier option when receiving a DHCP ACK or NAK to make
sure that it matches that of our associated DHCP server. Normalize, prune, and beautify the appearance of log messages. Minor cosmetic cleanups/refactoring.
This commit is contained in:
parent
e0ef11848b
commit
cfa22626e4
23
ndhc/arp.c
23
ndhc/arp.c
@ -201,17 +201,17 @@ static int arp_open_fd(struct client_state_t *cs)
|
||||
|
||||
int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
|
||||
if (fd == -1) {
|
||||
log_error("arp: failed to create socket: %s", strerror(errno));
|
||||
log_error("arp: Failed to create socket: %s", strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof opt) == -1) {
|
||||
log_error("arp: failed to set broadcast: %s", strerror(errno));
|
||||
log_error("arp: Failed to set broadcast: %s", strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == -1) {
|
||||
log_error("arp: failed to set non-blocking: %s", strerror(errno));
|
||||
log_error("arp: Failed to set non-blocking: %s", strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
struct sockaddr_ll saddr = {
|
||||
@ -246,7 +246,7 @@ static void arp_switch_state(struct client_state_t *cs, arp_state_t state)
|
||||
}
|
||||
if (cs->arpFd == -1) {
|
||||
if (arp_open_fd(cs) == -1)
|
||||
suicide("arp: failed to open arpFd when changing state to %u",
|
||||
suicide("arp: Failed to open arpFd when changing state to %u",
|
||||
arpState);
|
||||
if (arpState != AS_DEFENSE)
|
||||
arp_set_bpf_basic(cs->arpFd);
|
||||
@ -285,8 +285,8 @@ static int arp_reopen_fd(struct client_state_t *cs)
|
||||
arp_state_t prev_state = arpState;
|
||||
arp_min_close_fd(cs);
|
||||
if (arp_open_fd(cs) == -1) {
|
||||
log_warning("arp_reopen_fd: Failed to open. Something is very wrong.");
|
||||
log_warning("arp_reopen_fd: Client will still run, but functionality will be degraded.");
|
||||
log_warning("arp: Failed to re-open fd. Something is very wrong.");
|
||||
log_warning("arp: Client will still run, but functionality will be degraded.");
|
||||
return -1;
|
||||
}
|
||||
arp_switch_state(cs, prev_state);
|
||||
@ -303,7 +303,7 @@ static int arp_send(struct client_state_t *cs, struct arpMsg *arp)
|
||||
memcpy(addr.sll_addr, client_config.arp, 6);
|
||||
|
||||
if (cs->arpFd == -1) {
|
||||
log_warning("arp_send: Send attempted when no ARP fd is open.");
|
||||
log_warning("arp: Send attempted when no ARP fd is open.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -403,6 +403,7 @@ int arp_gw_check(struct client_state_t *cs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Should only be called from DS_BOUND state.
|
||||
static int arp_get_gw_hwaddr(struct client_state_t *cs)
|
||||
{
|
||||
if (cs->dhcpState != DS_BOUND)
|
||||
@ -428,7 +429,7 @@ static int arp_get_gw_hwaddr(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);
|
||||
arp_wake_ts[AS_COLLISION_CHECK] = -1;
|
||||
reinit_selecting(cs, total_conflicts < MAX_CONFLICTS ?
|
||||
@ -464,7 +465,7 @@ void arp_set_defense_mode(struct client_state_t *cs)
|
||||
void arp_success(struct client_state_t *cs)
|
||||
{
|
||||
struct in_addr temp_addr = {.s_addr = arp_dhcp_packet.yiaddr};
|
||||
log_line("arp: Lease of %s obtained, lease time %ld",
|
||||
log_line("Lease of %s obtained. Lease time is %ld seconds.",
|
||||
inet_ntoa(temp_addr), cs->lease);
|
||||
cs->clientAddr = arp_dhcp_packet.yiaddr;
|
||||
cs->dhcpState = DS_BOUND;
|
||||
@ -494,7 +495,7 @@ void arp_success(struct client_state_t *cs)
|
||||
|
||||
static void arp_gw_success(struct client_state_t *cs)
|
||||
{
|
||||
log_line("arp: Network seems unchanged");
|
||||
log_line("arp: Network seems unchanged. Resuming normal operation.");
|
||||
arp_switch_state(cs, AS_DEFENSE);
|
||||
arp_announcement(cs);
|
||||
|
||||
@ -645,7 +646,7 @@ static void arp_do_defense(struct client_state_t *cs)
|
||||
if (!arp_validate_bpf_defense(cs, &arpreply))
|
||||
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();
|
||||
arp_wake_ts[AS_DEFENSE] = -1;
|
||||
if (!last_conflict_ts ||
|
||||
|
37
ndhc/dhcp.c
37
ndhc/dhcp.c
@ -62,12 +62,12 @@ static int create_udp_socket(uint32_t ip, uint16_t port, char *iface)
|
||||
}
|
||||
int opt = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) == -1) {
|
||||
log_error("create_udp_socket: set reuse addr failed: %s",
|
||||
log_error("create_udp_socket: Set reuse addr failed: %s",
|
||||
strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof opt) == -1) {
|
||||
log_error("create_udp_socket: set don't route failed: %s",
|
||||
log_error("create_udp_socket: Set don't route failed: %s",
|
||||
strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
@ -75,12 +75,12 @@ static int create_udp_socket(uint32_t ip, uint16_t port, char *iface)
|
||||
memset(&ifr, 0, sizeof (struct ifreq));
|
||||
strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr) < 0) {
|
||||
log_error("create_udp_socket: set bind to device failed: %s",
|
||||
log_error("create_udp_socket: Set bind to device failed: %s",
|
||||
strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == -1) {
|
||||
log_error("create_udp_socket: set non-blocking failed: %s",
|
||||
log_error("create_udp_socket: Set non-blocking failed: %s",
|
||||
strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
@ -109,7 +109,7 @@ static int create_udp_listen_socket(struct client_state_t *cs, char *inf)
|
||||
return -1;
|
||||
int opt = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof opt) == -1) {
|
||||
log_error("create_udp_listen_socket: set broadcast failed: %s",
|
||||
log_error("create_udp_listen_socket: Set broadcast failed: %s",
|
||||
strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
@ -138,7 +138,7 @@ static int send_dhcp_cooked(struct client_state_t *cs, struct dhcpmsg *payload)
|
||||
|
||||
ssize_t endloc = get_end_option_idx(payload);
|
||||
if (endloc < 0) {
|
||||
log_error("send_dhcp_cooked: attempt to send packet with no DHCP_END");
|
||||
log_error("send_dhcp_cooked: Attempt to send packet with no DHCP_END.");
|
||||
goto out_fd;
|
||||
}
|
||||
size_t payload_len =
|
||||
@ -236,11 +236,11 @@ static int udp_checksum(struct ip_udp_dhcp_packet *packet)
|
||||
static int get_raw_packet_validate_bpf(struct ip_udp_dhcp_packet *packet)
|
||||
{
|
||||
if (packet->ip.version != IPVERSION) {
|
||||
log_line("IP version is not IPv4");
|
||||
log_line("IP version is not IPv4.");
|
||||
return 0;
|
||||
}
|
||||
if (packet->ip.ihl != sizeof packet->ip >> 2) {
|
||||
log_line("IP header length incorrect");
|
||||
log_line("IP header length incorrect.");
|
||||
return 0;
|
||||
}
|
||||
if (packet->ip.protocol != IPPROTO_UDP) {
|
||||
@ -253,7 +253,7 @@ static int get_raw_packet_validate_bpf(struct ip_udp_dhcp_packet *packet)
|
||||
}
|
||||
if (ntohs(packet->udp.len) !=
|
||||
ntohs(packet->ip.tot_len) - sizeof packet->ip) {
|
||||
log_line("UDP header length incorrect");
|
||||
log_line("UDP header length incorrect.");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@ -281,11 +281,11 @@ static int get_raw_packet(struct client_state_t *cs, struct dhcpmsg *payload)
|
||||
return -2;
|
||||
|
||||
if (!ip_checksum(&packet)) {
|
||||
log_line("IP header checksum incorrect");
|
||||
log_line("IP header checksum incorrect.");
|
||||
return -2;
|
||||
}
|
||||
if (packet.udp.check && !udp_checksum(&packet)) {
|
||||
log_error("Packet with bad UDP checksum received, ignoring");
|
||||
log_error("Packet with bad UDP checksum received. Ignoring.");
|
||||
return -2;
|
||||
}
|
||||
|
||||
@ -313,12 +313,12 @@ static int create_raw_socket(struct client_state_t *cs, struct sockaddr_ll *sa,
|
||||
|
||||
int opt = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof opt) == -1) {
|
||||
log_error("create_raw_socket: failed to set don't route: %s",
|
||||
log_error("create_raw_socket: Failed to set don't route: %s",
|
||||
strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == -1) {
|
||||
log_error("create_raw_socket: set non-blocking failed: %s",
|
||||
log_error("create_raw_socket: Set non-blocking failed: %s",
|
||||
strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
@ -399,7 +399,7 @@ static int send_dhcp_raw(struct dhcpmsg *payload)
|
||||
// and drop packets that are longer than 562 bytes.
|
||||
ssize_t endloc = get_end_option_idx(payload);
|
||||
if (endloc < 0) {
|
||||
log_error("send_dhcp_raw: attempt to send packet with no DHCP_END");
|
||||
log_error("send_dhcp_raw: Attempt to send packet with no DHCP_END.");
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
@ -452,20 +452,16 @@ static void change_listen_mode(struct client_state_t *cs, int new_mode)
|
||||
close(cs->listenFd);
|
||||
cs->listenFd = -1;
|
||||
}
|
||||
if (new_mode == LM_NONE) {
|
||||
log_line("Stopped listening for DHCP packets.");
|
||||
if (new_mode == LM_NONE)
|
||||
return;
|
||||
}
|
||||
cs->listenFd = new_mode == LM_RAW ?
|
||||
create_raw_listen_socket(cs, client_config.ifindex) :
|
||||
create_udp_listen_socket(cs, client_config.interface);
|
||||
if (cs->listenFd < 0) {
|
||||
log_error("FATAL: couldn't listen on socket: %s.", strerror(errno));
|
||||
log_error("FATAL: Couldn't listen on socket: %s.", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
epoll_add(cs, cs->listenFd);
|
||||
log_line("Listening for DHCP packets using a %s socket.",
|
||||
new_mode == LM_RAW ? "raw" : "cooked");
|
||||
}
|
||||
|
||||
void set_listen_raw(struct client_state_t *cs)
|
||||
@ -529,7 +525,6 @@ void handle_packet(struct client_state_t *cs)
|
||||
|
||||
if (!validate_dhcp_packet(cs, len, &packet, &message))
|
||||
return;
|
||||
log_line("Received a reply.");
|
||||
packet_action(cs, &packet, message);
|
||||
}
|
||||
|
||||
|
@ -55,10 +55,10 @@ static void get_if_index_and_mac(const struct nlmsghdr *nlh,
|
||||
if (!strcmp(client_config.interface, nlattr_get_data(tb[IFLA_IFNAME]))) {
|
||||
client_config.ifindex = ifm->ifi_index;
|
||||
if (!tb[IFLA_ADDRESS])
|
||||
suicide("FATAL: adapter %s lacks a hardware address");
|
||||
suicide("FATAL: Adapter %s lacks a hardware address.");
|
||||
int maclen = nlattr_get_len(tb[IFLA_ADDRESS]) - 4;
|
||||
if (maclen != 6)
|
||||
suicide("FATAL: adapter hardware address length should be 6, but is %u",
|
||||
suicide("FATAL: Adapter hardware address length should be 6, but is %u.",
|
||||
maclen);
|
||||
|
||||
const unsigned char *mac =
|
||||
@ -105,7 +105,7 @@ static int nl_process_msgs(const struct nlmsghdr *nlh, void *data)
|
||||
break;
|
||||
if (cs->ifsPrevState != IFS_REMOVED) {
|
||||
cs->ifsPrevState = IFS_REMOVED;
|
||||
log_line("Interface removed; exiting.");
|
||||
log_line("Interface removed. Exiting.");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
break;
|
||||
|
16
ndhc/nl.c
16
ndhc/nl.c
@ -45,11 +45,11 @@ ssize_t nl_recv_buf(int fd, char *buf, size_t blen)
|
||||
return -1;
|
||||
}
|
||||
if (msg.msg_flags & MSG_TRUNC) {
|
||||
log_error("nl_fill_buf: buffer not long enough for message");
|
||||
log_error("nl_fill_buf: Buffer not long enough for message.");
|
||||
return -1;
|
||||
}
|
||||
if (msg.msg_namelen != sizeof addr) {
|
||||
log_error("nl_fill_buf: response was not of the same address family");
|
||||
log_error("nl_fill_buf: Response was not of the same address family.");
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
@ -72,13 +72,13 @@ int nl_foreach_nlmsg(char *buf, size_t blen, int portid,
|
||||
} else {
|
||||
switch (nlh->nlmsg_type) {
|
||||
case NLMSG_ERROR:
|
||||
log_line("nl: received a NLMSG_ERROR: %s",
|
||||
log_line("nl: Received a NLMSG_ERROR: %s",
|
||||
strerror(nlmsg_get_error(nlh)));
|
||||
return -1;
|
||||
case NLMSG_DONE:
|
||||
return 0;
|
||||
case NLMSG_OVERRUN:
|
||||
log_line("nl: received a NLMSG_OVERRUN");
|
||||
log_line("nl: Received a NLMSG_OVERRUN.");
|
||||
case NLMSG_NOOP:
|
||||
default:
|
||||
break;
|
||||
@ -98,11 +98,11 @@ int nl_open(int nltype, int nlgroup, int *nlportid)
|
||||
return -1;
|
||||
}
|
||||
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) == -1) {
|
||||
log_error("nl_open: set non-blocking failed: %s", strerror(errno));
|
||||
log_error("nl_open: Set non-blocking failed: %s", strerror(errno));
|
||||
goto err_close;
|
||||
}
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
|
||||
log_error("nl_open: set close-on-exec failed: %s", strerror(errno));
|
||||
log_error("nl_open: Set close-on-exec failed: %s", strerror(errno));
|
||||
goto err_close;
|
||||
}
|
||||
socklen_t al;
|
||||
@ -120,11 +120,11 @@ int nl_open(int nltype, int nlgroup, int *nlportid)
|
||||
goto err_close;
|
||||
}
|
||||
if (al != sizeof nlsock) {
|
||||
log_error("nl_open: bound socket doesn't have right family size");
|
||||
log_error("nl_open: Bound socket doesn't have right family size.");
|
||||
goto err_close;
|
||||
}
|
||||
if (nlsock.nl_family != AF_NETLINK) {
|
||||
log_error("nl_open: bound socket isn't AF_NETLINK");
|
||||
log_error("nl_open: Bound socket isn't AF_NETLINK.");
|
||||
goto err_close;
|
||||
}
|
||||
if (nlportid)
|
||||
|
54
ndhc/state.c
54
ndhc/state.c
@ -116,12 +116,6 @@ static void bound_timeout(struct client_state_t *cs, long long nowts)
|
||||
renewing_timeout(cs, nowts);
|
||||
}
|
||||
|
||||
static void lease_timedout(struct client_state_t *cs)
|
||||
{
|
||||
log_line("Lease lost, entering init state.");
|
||||
reinit_selecting(cs, 0);
|
||||
}
|
||||
|
||||
// Triggered when a DHCP renew request has been sent and no reply has been
|
||||
// received within the response wait time. This function is also directly
|
||||
// called by bound_timeout() when it is time to renew a lease before it
|
||||
@ -159,8 +153,10 @@ static void rebinding_timeout(struct client_state_t *cs, long long nowts)
|
||||
}
|
||||
send_rebind(cs);
|
||||
dhcp_wake_ts = nowts + ((elt - nowts) / 2);
|
||||
} else
|
||||
lease_timedout(cs);
|
||||
} else {
|
||||
log_line("Lease expired. Searching for a new lease...");
|
||||
reinit_selecting(cs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void released_timeout(struct client_state_t *cs, long long nowts)
|
||||
@ -168,11 +164,32 @@ static void released_timeout(struct client_state_t *cs, long long nowts)
|
||||
dhcp_wake_ts = -1;
|
||||
}
|
||||
|
||||
static int validate_serverid(struct client_state_t *cs, struct dhcpmsg *packet,
|
||||
char *typemsg)
|
||||
{
|
||||
uint8_t *temp = NULL;
|
||||
ssize_t optlen;
|
||||
if (!(temp = get_option_data(packet, DHCP_SERVER_ID, &optlen))) {
|
||||
log_line("Received %s with no server id. Ignoring it.");
|
||||
return 0;
|
||||
}
|
||||
if (memcmp(&cs->serverAddr, temp, 4)) {
|
||||
uint32_t iptmp;
|
||||
memcpy(&iptmp, temp, 4);
|
||||
log_line("Received %s with an unexpected server id: %s. Ignoring it.",
|
||||
typemsg, inet_ntoa((struct in_addr){.s_addr=iptmp}));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Can transition to DS_BOUND or DS_SELECTING.
|
||||
static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet,
|
||||
uint8_t *message)
|
||||
{
|
||||
if (*message == DHCPACK) {
|
||||
if (!validate_serverid(cs, packet, "a DHCP ACK"))
|
||||
return;
|
||||
ssize_t optlen;
|
||||
uint8_t *temp = get_option_data(packet, DHCP_LEASE_TIME, &optlen);
|
||||
cs->leaseStartTime = curms();
|
||||
@ -197,18 +214,23 @@ static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet,
|
||||
// have received a lease with a different IP than what we had before.
|
||||
if (cs->dhcpState == DS_REQUESTING ||
|
||||
memcmp(&packet->yiaddr, &cs->clientAddr, 4)) {
|
||||
log_line("Accepted a firm offer for %s. Validating...",
|
||||
inet_ntoa((struct in_addr){.s_addr=cs->clientAddr}));
|
||||
if (arp_check(cs, packet) == -1) {
|
||||
log_warning("arp_check failed to make arp socket, retrying lease");
|
||||
log_warning("Failed to make arp socket. Searching for new lease...");
|
||||
reinit_selecting(cs, 3000);
|
||||
}
|
||||
} else {
|
||||
log_line("Lease refreshed to %u seconds.", cs->lease);
|
||||
cs->dhcpState = DS_BOUND;
|
||||
arp_set_defense_mode(cs);
|
||||
set_listen_none(cs);
|
||||
}
|
||||
|
||||
} else if (*message == DHCPNAK) {
|
||||
log_line("Received DHCP NAK.");
|
||||
if (!validate_serverid(cs, packet, "a DHCP NAK"))
|
||||
return;
|
||||
log_line("Our request was rejected. Searching for a new lease...");
|
||||
reinit_selecting(cs, 3000);
|
||||
}
|
||||
}
|
||||
@ -226,8 +248,11 @@ static void selecting_packet(struct client_state_t *cs, struct dhcpmsg *packet,
|
||||
cs->dhcpState = DS_REQUESTING;
|
||||
dhcp_wake_ts = curms();
|
||||
num_dhcp_requests = 0;
|
||||
log_line("Received an offer of %s from server %s.",
|
||||
inet_ntoa((struct in_addr){.s_addr=cs->clientAddr}),
|
||||
inet_ntoa((struct in_addr){.s_addr=cs->serverAddr}));
|
||||
} else {
|
||||
log_line("No server ID in message");
|
||||
log_line("Invalid offer received: it didn't have a server id.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -289,14 +314,15 @@ void ifup_action(struct client_state_t *cs)
|
||||
cs->dhcpState == DS_RENEWING ||
|
||||
cs->dhcpState == DS_REBINDING)) {
|
||||
if (arp_gw_check(cs) != -1) {
|
||||
log_line("nl: interface back, revalidating lease");
|
||||
log_line("nl: Interface is back. Revalidating lease...");
|
||||
return;
|
||||
} else
|
||||
log_warning("nl: arp_gw_check could not make arp socket");
|
||||
log_warning("nl: arp_gw_check could not make arp socket.");
|
||||
}
|
||||
if (cs->dhcpState == DS_SELECTING)
|
||||
return;
|
||||
log_line("nl: %s back, querying for new lease", client_config.interface);
|
||||
log_line("nl: %s is back. Searching for new lease...",
|
||||
client_config.interface);
|
||||
reinit_selecting(cs, 0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user