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:
Nicholas J. Kain 2011-07-11 16:33:57 -04:00
parent e0ef11848b
commit cfa22626e4
5 changed files with 79 additions and 57 deletions

View File

@ -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 ||

View File

@ -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);
}

View File

@ -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;

View File

@ -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)

View File

@ -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);
}