waiting special network interface added
#include <errno.h>
#include <stdio.h>
#include <poll.h>
#include <memory.h>
#include <unistd.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <linux/rtnetlink.h>
void parseRtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
{
memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
while (RTA_OK(rta, len)) {
if (rta->rta_type <= max) {
tb[rta->rta_type] = rta;
}
rta = RTA_NEXT(rta,len);
}
}
static int matchInterface(const char *interface, char *argv[], int argc)
{
int i;
int result = 0;
for (i = 1; i < argc; i++) {
const char *pattern = argv[i];
const char *name = interface;
while (*pattern == *interface && *interface) {
interface++;
pattern++;
}
fprintf(stderr, "pattern: %s interface %s\n", pattern, interface);
if (*pattern == 0 && *interface == 0) {
result = 1;
break;
}
if (*pattern == '+' && *interface) {
result = 1;
break;
}
if (*pattern == '*') {
result = 1;
break;
}
}
return result;
}
int main(int argc, char *argv[])
{
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) {
printf("Failed to create netlink socket: %s\n", (char*)strerror(errno));
return 1;
}
char buf[8192];
struct sockaddr_nl local;
struct iovec iov;
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_groups = RTMGRP_LINK;
local.nl_pid = getpid();
struct msghdr msg;
msg.msg_name = &local;
msg.msg_namelen = sizeof(local);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
printf("Failed to bind netlink socket: %s\n", (char*)strerror(errno));
close(fd);
return 1;
}
do {
struct pollfd one;
one.fd = fd;
one.events = POLLIN;
poll(&one, 1, 250);
ssize_t status = recvmsg(fd, &msg, MSG_DONTWAIT);
if (status < 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
printf("Failed to read netlink: %s", (char*)strerror(errno));
continue;
}
if (msg.msg_namelen != sizeof(local)) {
printf("Invalid length of the sender address struct\n");
continue;
}
// message parser
struct nlmsghdr *h;
for (h = (struct nlmsghdr*)buf; status >= (ssize_t)sizeof(*h); ) {
int len = h->nlmsg_len;
int l = len - sizeof(*h);
char *ifName;
if ((l < 0) || (len > status)) {
printf("Invalid message length: %i\n", len);
continue;
}
// now we can check message type
if ((h->nlmsg_type == RTM_NEWROUTE) || (h->nlmsg_type == RTM_DELROUTE)) {
printf("Routing table was changed\n");
} else {
char *ifUpp;
char *ifRunn;
struct ifinfomsg *ifi;
struct rtattr *tb[IFLA_MAX + 1];
ifi = (struct ifinfomsg*) NLMSG_DATA(h);
parseRtattr(tb, IFLA_MAX, IFLA_RTA(ifi), h->nlmsg_len);
if (tb[IFLA_IFNAME]) {
ifName = (char*)RTA_DATA(tb[IFLA_IFNAME]);
}
if (ifi->ifi_flags & IFF_UP) {
ifUpp = (char*)"UP";
} else {
ifUpp = (char*)"DOWN";
}
if (ifi->ifi_flags & IFF_RUNNING) {
ifRunn = (char*)"RUNNING";
} else {
ifRunn = (char*)"NOT RUNNING";
}
char ifAddress[256];
struct ifaddrmsg *ifa;
struct rtattr *tba[IFA_MAX+1];
ifa = (struct ifaddrmsg*)NLMSG_DATA(h);
parseRtattr(tba, IFA_MAX, IFA_RTA(ifa), h->nlmsg_len);
if (tba[IFA_LOCAL]) {
inet_ntop(AF_INET, RTA_DATA(tba[IFA_LOCAL]), ifAddress, sizeof(ifAddress));
}
switch (h->nlmsg_type) {
case RTM_DELADDR:
printf("Interface %s: address was removed\n", ifName);
break;
case RTM_DELLINK:
printf("Network interface %s was removed\n", ifName);
break;
case RTM_NEWLINK:
printf("New network interface %s, state: %s %s\n", ifName, ifUpp, ifRunn);
if (matchInterface(ifName, argv, argc)) goto okay;
break;
case RTM_NEWADDR:
printf("Interface %s: new address was assigned: %s\n", ifName, ifAddress);
break;
}
}
status -= NLMSG_ALIGN(len);
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
}
} while ( 1 );
okay:
close(fd); // close socket
return 0;
}
Comments
Post a Comment