From 22fede861f576e3d34147fa040047fb4154addda Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Mon, 17 Mar 2014 05:56:30 -0400 Subject: [PATCH] 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. --- ndhc/ifset.c | 17 +++++++ ndhc/ifset.h | 1 + ndhc/ndhc.c | 21 ++++++--- ndhc/netlink.c | 119 +++++++++++++++++++++++++++++++++---------------- ndhc/netlink.h | 4 +- 5 files changed, 117 insertions(+), 45 deletions(-) diff --git a/ndhc/ifset.c b/ndhc/ifset.c index 0b0349a..91bfaed 100644 --- a/ndhc/ifset.c +++ b/ndhc/ifset.c @@ -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) diff --git a/ndhc/ifset.h b/ndhc/ifset.h index 313072e..19cdbf2 100644 --- a/ndhc/ifset.h +++ b/ndhc/ifset.h @@ -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); diff --git a/ndhc/ndhc.c b/ndhc/ndhc.c index 3522281..fa714a5 100644 --- a/ndhc/ndhc.c +++ b/ndhc/ndhc.c @@ -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); diff --git a/ndhc/netlink.c b/ndhc/netlink.c index 4001de3..3cfe962 100644 --- a/ndhc/netlink.c +++ b/ndhc/netlink.c @@ -26,6 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -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; +} + diff --git a/ndhc/netlink.h b/ndhc/netlink.h index 06b04db..e2e3d7a 100644 --- a/ndhc/netlink.h +++ b/ndhc/netlink.h @@ -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_ */