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

Popular Posts