Netlink is pickier than the ioctl interfaces and requires the link to

manually be set to an 'up' state before much of anything can be changed.
Ensure that this is done very early in ndhc's lifetime, and record the
link status at startup time so that the hardware link status monitoring
will not get confused.  A perform_ifup() function is added to faciliate
this need.

Handle nl_getifdata() and get_if_index_and_mac() separately from the
hardware link status monitoring; don't call get_if_index_and_mac() from
nl_process_msgs().

Create the permanent ndhc-master cs.nlFd socket for hardware link status
monitoring after forking subprocesses.
This commit is contained in:
Nicholas J. Kain 2014-03-17 05:56:30 -04:00
parent 13aa5e6403
commit 22fede861f
5 changed files with 117 additions and 45 deletions

View File

@ -483,6 +483,23 @@ static ssize_t rtnl_if_mtu_set(int fd, unsigned int mtu)
return rtnl_do_send(fd, request, header->nlmsg_len, __func__);
}
int perform_ifup(void)
{
int fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (fd < 0) {
log_line("%s: (%s) netlink socket open failed: %s",
client_config.interface, __func__, strerror(errno));
return fd;
}
int r = link_set_flags(fd, IFF_UP);
if (r < 0)
log_line("%s: (%s) Failed to set link to be up.",
client_config.interface, __func__);
close(fd);
return r;
}
// str_bcast is optional.
void perform_ip_subnet_bcast(const char *str_ipaddr,
const char *str_subnet, const char *str_bcast)

View File

@ -28,6 +28,7 @@
#ifndef NJK_IFSET_H_
#define NJK_IFSET_H_
extern int perform_ifup(void);
extern void perform_ip_subnet_bcast(const char *str_ipaddr,
const char *str_subnet,
const char *str_bcast);

View File

@ -60,6 +60,7 @@
#include "nl.h"
#include "netlink.h"
#include "leasefile.h"
#include "ifset.h"
#include "log.h"
#include "chroot.h"
@ -343,6 +344,11 @@ static void ndhc_main(void) {
log_line("ndhc client " NDHC_VERSION " started on interface [%s].",
client_config.interface);
if ((cs.nlFd = nl_open(NETLINK_ROUTE, RTMGRP_LINK, &cs.nlPortId)) < 0) {
log_line("FATAL - failed to open netlink socket");
exit(EXIT_FAILURE);
}
if (client_config.foreground && !client_config.background_if_no_lease) {
if (file_exists(pidfile, "w") == -1) {
log_line("FATAL - can't open pidfile '%s' for write!", pidfile);
@ -573,12 +579,18 @@ int main(int argc, char **argv)
if (!strncmp(chroot_dir, "", sizeof chroot_dir))
suicide("FATAL - No chroot path specified. Refusing to run.");
if ((cs.nlFd = nl_open(NETLINK_ROUTE, RTMGRP_LINK, &cs.nlPortId)) < 0) {
log_line("FATAL - failed to open netlink socket");
if (nl_getifdata() < 0) {
log_line("FATAL - failed to get interface MAC or index");
exit(EXIT_FAILURE);
}
if (nl_getifdata(&cs) < 0) {
log_line("FATAL - failed to get interface MAC and index");
switch (perform_ifup()) {
case 1:
cs.ifsPrevState = IFS_UP;
case 0:
break;
default:
log_error("FATAL - failed to set the interface to up state");
exit(EXIT_FAILURE);
}
@ -587,7 +599,6 @@ int main(int argc, char **argv)
if (ifch_pid == 0) {
close(pToNdhcR);
close(pToIfchW);
close(cs.nlFd);
ifch_main();
} else if (ifch_pid > 0) {
close(pToIfchR);

View File

@ -26,6 +26,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <unistd.h>
#include <arpa/inet.h>
#include <assert.h>
#include <asm/types.h>
@ -51,33 +52,6 @@ static int nlattr_assign(struct nlattr *attr, int type, void *data)
return 0;
}
static void get_if_index_and_mac(const struct nlmsghdr *nlh,
struct ifinfomsg *ifm)
{
struct nlattr *tb[IFLA_MAX] = {0};
nl_attr_parse(nlh, sizeof *ifm, nlattr_assign, tb);
if (!tb[IFLA_IFNAME])
return;
if (!strncmp(client_config.interface,
nlattr_get_data(tb[IFLA_IFNAME]),
sizeof client_config.interface)) {
client_config.ifindex = ifm->ifi_index;
if (!tb[IFLA_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.",
maclen);
const unsigned char *mac =
(unsigned char *)nlattr_get_data(tb[IFLA_ADDRESS]);
log_line("%s hardware address %x:%x:%x:%x:%x:%x",
client_config.interface,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
memcpy(client_config.arp, mac, 6);
}
}
static void nl_process_msgs(const struct nlmsghdr *nlh, void *data)
{
struct ifinfomsg *ifm = nlmsg_get_data(nlh);
@ -85,8 +59,6 @@ static void nl_process_msgs(const struct nlmsghdr *nlh, void *data)
switch(nlh->nlmsg_type) {
case RTM_NEWLINK:
if (!client_config.ifindex)
get_if_index_and_mac(nlh, ifm);
if (ifm->ifi_index != client_config.ifindex)
break;
// IFF_UP corresponds to ifconfig down or ifconfig up.
@ -137,18 +109,89 @@ void handle_nl_message(struct client_state_t *cs)
} while (ret > 0);
}
int nl_getifdata(struct client_state_t *cs)
static int get_if_index_and_mac(const struct nlmsghdr *nlh,
struct ifinfomsg *ifm)
{
if (nl_sendgetlinks(cs->nlFd, time(NULL)))
return -1;
struct nlattr *tb[IFLA_MAX] = {0};
nl_attr_parse(nlh, sizeof *ifm, nlattr_assign, tb);
if (tb[IFLA_IFNAME] && !strncmp(client_config.interface,
nlattr_get_data(tb[IFLA_IFNAME]),
sizeof client_config.interface)) {
client_config.ifindex = ifm->ifi_index;
if (!tb[IFLA_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.",
maclen);
for (int pr = 0; !pr;) {
pr = poll(&((struct pollfd){.fd=cs->nlFd,.events=POLLIN}), 1, -1);
if (pr == 1)
handle_nl_message(cs);
else if (pr == -1)
suicide("nl: poll failed");
const unsigned char *mac =
(unsigned char *)nlattr_get_data(tb[IFLA_ADDRESS]);
log_line("%s hardware address %x:%x:%x:%x:%x:%x",
client_config.interface,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
memcpy(client_config.arp, mac, 6);
return 1;
}
return 0;
}
static void do_handle_getifdata(const struct nlmsghdr *nlh, void *data)
{
int *got_ifdata = (int *)data;
struct ifinfomsg *ifm = nlmsg_get_data(nlh);
switch(nlh->nlmsg_type) {
case RTM_NEWLINK:
*got_ifdata |= get_if_index_and_mac(nlh, ifm);
break;
default:
break;
}
}
static int handle_getifdata(int fd)
{
char nlbuf[8192];
ssize_t ret;
int got_ifdata = 0;
do {
ret = nl_recv_buf(fd, nlbuf, sizeof nlbuf);
if (ret == -1)
return -1;
if (nl_foreach_nlmsg(nlbuf, ret, 0, 0,
do_handle_getifdata, &got_ifdata) == -1)
return -1;
} while (ret > 0);
return got_ifdata ? 0 : -1;
}
int nl_getifdata(void)
{
int ret = -1;
int fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (fd < 0) {
log_line("%s: (%s) netlink socket open failed: %s",
client_config.interface, __func__, strerror(errno));
goto fail;
}
if (nl_sendgetlinks(fd, time(NULL))) {
log_line("%s: (%s) nl_sendgetlinks failed",
client_config.interface, __func__);
goto fail_fd;
}
for (int pr = 0; !pr;) {
pr = poll(&((struct pollfd){.fd=fd,.events=POLLIN}), 1, -1);
if (pr == 1)
ret = handle_getifdata(fd);
else if (pr == -1 && errno != EINTR)
goto fail_fd;
}
fail_fd:
close(fd);
fail:
return ret;
}

View File

@ -40,7 +40,7 @@ enum {
IFS_REMOVED
};
void handle_nl_message(struct client_state_t *cs);
int nl_getifdata(struct client_state_t *cs);
extern void handle_nl_message(struct client_state_t *cs);
extern int nl_getifdata(void);
#endif /* NK_NETLINK_H_ */