Use netlink for getting interface mac and index in ndhc instead of ioctl.
This commit is contained in:
parent
a53a82bbc5
commit
55bc002ad6
@ -11,6 +11,7 @@ set(NDHC_SRCS
|
||||
ifchange.c
|
||||
dhcpmsg.c
|
||||
arp.c
|
||||
netlink.c
|
||||
ndhc.c
|
||||
)
|
||||
|
||||
|
12
ndhc/ndhc.c
12
ndhc/ndhc.c
@ -52,6 +52,8 @@
|
||||
#include "ifchange.h"
|
||||
#include "socket.h"
|
||||
#include "arp.h"
|
||||
#include "netlink.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "chroot.h"
|
||||
#include "cap.h"
|
||||
@ -361,9 +363,14 @@ int main(int argc, char **argv)
|
||||
write_pid(pidfile);
|
||||
}
|
||||
|
||||
if (read_interface(client_config.interface, &client_config.ifindex,
|
||||
NULL, client_config.arp) < 0)
|
||||
if (nl_open() < 0) {
|
||||
log_line("FATAL - failed to open netlink socket");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (nl_getifdata(client_config.interface) < 0) {
|
||||
log_line("FATAL - failed to get interface MAC and index");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!client_config.clientid) {
|
||||
client_config.clientid = xmalloc(6 + 3);
|
||||
@ -391,5 +398,6 @@ int main(int argc, char **argv)
|
||||
|
||||
do_work();
|
||||
|
||||
nl_close();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
217
ndhc/netlink.c
Normal file
217
ndhc/netlink.c
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright 2011 Nicholas J. Kain <njkain@gmail.com>
|
||||
* Copyright 2006, 2007 Stefan Rompf <sux@loplof.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <asm/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "netlink.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
|
||||
// OS_REMOVED -> exit
|
||||
// OS_SHUT -> exit
|
||||
// OS_DOWN -> action
|
||||
// OS_UP -> action
|
||||
|
||||
#define NLMSG_RECVSIZE 8192
|
||||
|
||||
static int nl_socket = -1;
|
||||
static unsigned int nl_seq;
|
||||
|
||||
/* internal callback handling */
|
||||
static void (*nlcb_function)(struct nlmsghdr *msg, void **args);
|
||||
static void *nlcb_args[3];
|
||||
static __u32 nlcb_pid;
|
||||
static unsigned int nlcb_seq;
|
||||
static char nlcb_run;
|
||||
|
||||
int nl_open() {
|
||||
struct sockaddr_nl nlsock = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pad = 0,
|
||||
.nl_pid = getpid(),
|
||||
.nl_groups = RTMGRP_LINK
|
||||
};
|
||||
|
||||
nlcb_pid = nlsock.nl_pid;
|
||||
|
||||
assert(nl_socket == -1);
|
||||
|
||||
nl_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||
|
||||
if (nl_socket == -1) return -1;
|
||||
|
||||
if (bind(nl_socket, (const struct sockaddr *)&nlsock, sizeof(nlsock)))
|
||||
goto err_close;
|
||||
|
||||
if (fcntl(nl_socket, F_SETFD, FD_CLOEXEC))
|
||||
goto err_close;
|
||||
|
||||
return 0;
|
||||
|
||||
err_close:
|
||||
nl_close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void nl_close() {
|
||||
close(nl_socket);
|
||||
nl_socket = -1;
|
||||
}
|
||||
|
||||
void nl_queryifstatus(int ifidx) {
|
||||
struct {
|
||||
struct nlmsghdr hdr;
|
||||
struct ifinfomsg ifinfo;
|
||||
} req;
|
||||
|
||||
req.hdr.nlmsg_len = sizeof(req);
|
||||
req.hdr.nlmsg_type = RTM_GETLINK;
|
||||
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
||||
req.hdr.nlmsg_seq = ++nl_seq;
|
||||
req.hdr.nlmsg_pid = nlcb_pid;
|
||||
req.ifinfo.ifi_family = AF_UNSPEC;
|
||||
req.ifinfo.ifi_index = ifidx; /* Doesn't work... */
|
||||
req.ifinfo.ifi_flags = IFF_UP;
|
||||
req.ifinfo.ifi_change = 0xffffffff;
|
||||
|
||||
send(nl_socket, &req, sizeof(req),0);
|
||||
}
|
||||
|
||||
|
||||
static void nl_handlemsg(struct nlmsghdr *msg, unsigned int len) {
|
||||
if (len < sizeof(*msg)) return;
|
||||
|
||||
while(NLMSG_OK(msg,len)) {
|
||||
if (nlcb_run &&
|
||||
nlcb_pid == msg->nlmsg_pid &&
|
||||
nlcb_seq == msg->nlmsg_seq) {
|
||||
nlcb_function(msg, nlcb_args);
|
||||
|
||||
if (msg->nlmsg_type == NLMSG_DONE ||
|
||||
msg->nlmsg_type == NLMSG_ERROR) nlcb_run = 0;
|
||||
}
|
||||
|
||||
if (NLMSG_PAYLOAD(msg, msg->nlmsg_len) >= sizeof(struct ifinfomsg)) {
|
||||
struct ifinfomsg *ifinfo = NLMSG_DATA(msg);
|
||||
|
||||
switch(msg->nlmsg_type) {
|
||||
case RTM_NEWLINK:
|
||||
if (ifinfo->ifi_index != client_config.ifindex)
|
||||
break;
|
||||
if (ifinfo->ifi_flags & IFF_UP) {
|
||||
if (ifinfo->ifi_flags & IFF_RUNNING)
|
||||
printf("XXX_OS_UP() NYI\n");
|
||||
else
|
||||
printf("XXX_OS_DOWN() NYI\n");
|
||||
} else
|
||||
printf("XXX_OS_SHUT() NYI\n");
|
||||
break;
|
||||
case RTM_DELLINK:
|
||||
if (ifinfo->ifi_index != client_config.ifindex)
|
||||
break;
|
||||
printf("XXX_OS_REMOVED() NYI\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
msg = NLMSG_NEXT(msg,len);
|
||||
}
|
||||
}
|
||||
|
||||
static void nl_sync_dump() {
|
||||
char c[NLMSG_RECVSIZE];
|
||||
struct nlmsghdr *msg = (struct nlmsghdr *)c;
|
||||
int n;
|
||||
|
||||
nlcb_seq = nl_seq;
|
||||
for(nlcb_run = 1; nlcb_run;) {
|
||||
n = recv(nl_socket, c, NLMSG_RECVSIZE, 0);
|
||||
assert(n >= 0);
|
||||
nl_handlemsg(msg,n);
|
||||
}
|
||||
}
|
||||
|
||||
// Callback function for getting interface mac address and index.
|
||||
static void copy_ifdata(struct nlmsghdr *msg, void **args) {
|
||||
struct ifinfomsg *ifinfo = NLMSG_DATA(msg);
|
||||
struct rtattr *rta = IFLA_RTA(ifinfo);
|
||||
int len = NLMSG_PAYLOAD(msg, sizeof(*ifinfo));
|
||||
int found = 0;
|
||||
|
||||
if (msg->nlmsg_type != RTM_NEWLINK)
|
||||
return;
|
||||
if (client_config.ifindex)
|
||||
return;
|
||||
|
||||
for(; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
|
||||
switch(rta->rta_type) {
|
||||
case IFLA_IFNAME:
|
||||
if (!strncmp(client_config.interface,
|
||||
(char *)RTA_DATA(rta), RTA_PAYLOAD(rta))) {
|
||||
client_config.ifindex = ifinfo->ifi_index;
|
||||
log_line("adapter index %d", ifinfo->ifi_index);
|
||||
found |= 1;
|
||||
}
|
||||
break;
|
||||
case IFLA_ADDRESS:
|
||||
if (found != 1)
|
||||
break;
|
||||
/* We can only handle ethernet like devices with 6 octet MAC */
|
||||
if (RTA_PAYLOAD(rta) == 6) {
|
||||
memcpy(client_config.arp, RTA_DATA(rta), 6);
|
||||
log_line("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
client_config.arp[0], client_config.arp[1],
|
||||
client_config.arp[2], client_config.arp[3],
|
||||
client_config.arp[4], client_config.arp[5]);
|
||||
found |= 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == 3)
|
||||
nlcb_args[0] = (void *)1;
|
||||
}
|
||||
|
||||
// Gets interface mac address and index (synchronous).
|
||||
int nl_getifdata(const char *ifname) {
|
||||
struct {
|
||||
struct nlmsghdr hdr;
|
||||
struct ifinfomsg ifinfo;
|
||||
} req;
|
||||
|
||||
req.hdr.nlmsg_len = sizeof(req);
|
||||
req.hdr.nlmsg_type = RTM_GETLINK;
|
||||
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
||||
req.hdr.nlmsg_seq = ++nl_seq;
|
||||
req.hdr.nlmsg_pid = nlcb_pid;
|
||||
req.ifinfo.ifi_family = AF_UNSPEC;
|
||||
|
||||
if (send(nl_socket, &req, sizeof(req), 0) != sizeof(req)) return -1;
|
||||
|
||||
nlcb_function = copy_ifdata;
|
||||
nlcb_args[0] = NULL;
|
||||
|
||||
nl_sync_dump();
|
||||
|
||||
return nlcb_args[0]?0:-1;
|
||||
}
|
9
ndhc/netlink.h
Normal file
9
ndhc/netlink.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef NK_NETLINK_H_
|
||||
#define NK_NETLINK_H_
|
||||
|
||||
int nl_open();
|
||||
void nl_close();
|
||||
void nl_queryifstatus(int ifidx);
|
||||
int nl_getifdata(const char *ifname);
|
||||
|
||||
#endif /* NK_NETLINK_H_ */
|
@ -47,57 +47,6 @@ int set_sock_nonblock(int fd)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Given an interface name in @interface, return its index number,
|
||||
* IPv4 address, and MAC in @ifindex, @addr (optional), and @mac.*/
|
||||
int read_interface(char *interface, int *ifindex, uint32_t *addr, uint8_t *mac)
|
||||
{
|
||||
int fd, ret = -1;
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in *our_ip;
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
|
||||
log_error("socket failed!: %s", strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
|
||||
|
||||
if (addr) {
|
||||
if (ioctl(fd, SIOCGIFADDR, &ifr)) {
|
||||
log_error("Couldn't get IP for %s.", strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
|
||||
*addr = our_ip->sin_addr.s_addr;
|
||||
log_line("%s (our ip) = %s", ifr.ifr_name,
|
||||
inet_ntoa(our_ip->sin_addr));
|
||||
}
|
||||
|
||||
if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
|
||||
log_error("SIOCGIFINDEX failed!: %s", strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
|
||||
log_line("adapter index %d", ifr.ifr_ifindex);
|
||||
*ifindex = ifr.ifr_ifindex;
|
||||
|
||||
if (ioctl(fd, SIOCGIFHWADDR, &ifr)) {
|
||||
log_error("Couldn't get MAC for %s", strerror(errno));
|
||||
goto out_fd;
|
||||
}
|
||||
|
||||
memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
|
||||
log_line("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
ret = 0;
|
||||
out_fd:
|
||||
close(fd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns fd of new listen socket bound to @ip:@port on interface @inf
|
||||
* on success, or -1 on failure. */
|
||||
int listen_socket(unsigned int ip, int port, char *inf)
|
||||
|
@ -4,8 +4,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
int set_sock_nonblock(int fd);
|
||||
int read_interface(char *interface, int *ifindex, uint32_t *addr,
|
||||
uint8_t *mac);
|
||||
int listen_socket(unsigned int ip, int port, char *inf);
|
||||
int raw_socket(int ifindex);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user