tags:

views:

171

answers:

0

I'm currently trying to retrieve reachable neighbors from the arp table in a user space program written in c. I've looked through the source code to the "ip neigh" command (ipneigh.c) and it appears that I should use the flag NUD_REACHABLE to get the reachable nodes.

However, when I look at the data returned from the kernel, I only have stale entries. In fact, no matter what I put for req.r.ndm_state it seems to return only entries marked as stale by ip neigh!

I've included a sample app below (modeled after: http://linux-hacks.blogspot.com/2009/01/sample-code-to-learn-netlink.html) so that you can compile it and try it yourself.

How do I get reachable nodes to display as well?

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <linux/rtnetlink.h>

int main(int argc, char** argv) {
    struct {
        struct nlmsghdr n;
        struct ndmsg r;
    } req;

    struct rtattr *rta;
    int status;
    char buf[16384];
    struct nlmsghdr *nlmp;
    struct ndmsg *rtmp;
    struct rtattr *rtatp;
    int rtattrlen;
    struct in_addr *inp;

    char lladdr[6];
    char ipv4string[INET_ADDRSTRLEN];

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

    memset(&req, 0, sizeof(req));
    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
    req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_REQUEST;
    req.r.ndm_state = NUD_REACHABLE | NUD_DELAY; //TODO - get this working
    req.n.nlmsg_type = RTM_GETNEIGH;
    req.r.ndm_family = AF_INET; 

    rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
    rta->rta_len = RTA_LENGTH(4);

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

    if (status < 0) {
        //error sending
    }

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

    if (status < 0) {
        //error receiving
    }

    for(nlmp = (struct nlmsghdr *)buf; status > sizeof(*nlmp);){

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

        if (req_len<0 || len>status || !NLMSG_OK(nlmp, status)) {
            printf("error");
        }

        rtmp = (struct ndmsg *)NLMSG_DATA(nlmp);
        rtatp = (struct rtattr *)IFA_RTA(rtmp);

        rtattrlen = IFA_PAYLOAD(nlmp);

        for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) {       
            if(rtatp->rta_type == NDA_DST){
                inp = (struct in_addr *)RTA_DATA(rtatp);
                inet_ntop(AF_INET, inp, ipv4string, INET_ADDRSTRLEN);
                printf("addr: %s",ipv4string);
            }
            if(rtatp->rta_type == NDA_LLADDR){
                memcpy(lladdr, RTA_DATA(rtatp), 6);
                printf(" MAC: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
                            lladdr[0],
                            lladdr[1],
                            lladdr[2],
                            lladdr[3],
                            lladdr[4],
                            lladdr[5]);
            }
        }

        status -= NLMSG_ALIGN(len);
        nlmp = (struct nlmsghdr*)((char*)nlmp + NLMSG_ALIGN(len));
    }

    return 0;
}