#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>

int doit(int f)
{
    struct {
        struct nlmsghdr n;
        struct ifaddrmsg r;
    } req;

    int status;
    char buf[16384];
    struct nlmsghdr *nlmp = (struct nlmsghdr *) buf;
    struct ifaddrmsg *rtmp;
    struct rtattr *rtatp;
    int rtattrlen;

    int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);

    memset(&req, 0, sizeof(req));
    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
    req.n.nlmsg_type = RTM_GETADDR;

    req.r.ifa_family = f;

    status = send(fd, &req, req.n.nlmsg_len, 0);

    if (status < 0) {
        perror("send");
        return 0;
    }

    status = recv(fd, buf, sizeof(buf), 0);

    if (status < 0) {
        perror("recv");
        return 0;
    }

    if (status == 0) {
        printf("EOF\n");
        return 0;
    }

    while (status > sizeof(*nlmp)) {
        int len = nlmp->nlmsg_len;
        int req_len = len - sizeof(*nlmp);

        if (req_len < 0 || len > status) {
            printf("error\n");
            return 0;
        }

        if (!NLMSG_OK(nlmp, status)) {
            printf("NLMSG not OK\n");
            return 0;
        }

        rtmp = (struct ifaddrmsg *) NLMSG_DATA(nlmp);
        rtattrlen = IFA_PAYLOAD(nlmp);

        for (rtatp = (struct rtattr *) IFA_RTA(rtmp); RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) {
            // will only show up in ipv4 query... blah.
            if (rtatp->rta_type == IFA_LABEL) {
                printf("label if%i: %s\n", rtmp->ifa_index, (char *) RTA_DATA(rtatp));
            }

            if (rtatp->rta_type == IFA_ADDRESS) {
                char addr[200];
                inet_ntop(rtmp->ifa_family, RTA_DATA(rtatp), addr, sizeof(addr));
                printf("addr if%i: %s - scope = %i\n", rtmp->ifa_index, addr, rtmp->ifa_scope);
            }
        }
        status -= NLMSG_ALIGN(len);
        nlmp = (struct nlmsghdr *) ((char *) nlmp + NLMSG_ALIGN(len));
    }
    return 1;
}

int main(void) {
    if (!doit(AF_INET)) exit(-1);
    if (!doit(AF_INET6)) exit(-1);
    return 0;
}

