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:
parent
13aa5e6403
commit
22fede861f
17
ndhc/ifset.c
17
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)
|
||||
|
@ -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);
|
||||
|
21
ndhc/ndhc.c
21
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);
|
||||
|
119
ndhc/netlink.c
119
ndhc/netlink.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user