App not getting NUD_INCOMPLETE event even after registering.

LinuxQ

New Member
Joined
Jan 31, 2022
Messages
1
Reaction score
0
Credits
12
Application was interested in getting the NUD_INCOMPLETE but not received even after registering. Pls help in solving this issue.

Below is the program but failing to get NUD_INCOMPLETE. But gets below 3 events only not NUD_INCOMPLETE.
NUD_REACHABLE 0x02
NUD_STALE 0x04
NUD_NOARP 0x40

I am looking to getting IPv6 destination (even if its not resolved) when NUD_INCOMPLETE msg is received on application side.

NUD_INCOMPLETE a currently resolving cache entry

C++:
1. Create NeighSocket for monitering
bool ipv6::NeighCacheMonitor::CreateNeighTableSocket()
{
    neighTableFd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
    if(neighTableFd < 0)
    {
        cout << " socket() failed. err:" << errno
                << " errStr:" << std::strerror(errno));
        return false;
    }
    struct sockaddr_nl sockNl = {};
    sockNl.nl_family    = AF_NETLINK;

    int ret = bind(neighTableFd, (struct sockaddr*) &sockNl, sizeof(sockNl));
    if(ret < 0)
    {
        cout << " bind() failed. err:" << errno
                << " errStr:" << std::strerror(errno));
        return false;
    }
    return true;
}

2. Register for the msg types.

bool IPv6::NeighMonitor::SendGetNeighTableNLMsg()
{
    unsigned char localbuff[256];
    memset(localbuff, 0, sizeof(localbuff));
    struct nlmsghdr* nl = (struct nlmsghdr*)localbuff;

    nl->nlmsg_type  = RTM_GETNEIGH | RTM_NEWNEIGH | RTM_DELNEIGH;
    nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT;

    // initialize len as one rt msg
    struct ndmsg* nd    = NULL;

    nl->nlmsg_len       = NLMSG_LENGTH(sizeof(*nd));
    nd                  = (struct ndmsg*)NLMSG_DATA(nl);
    nd->ndm_family      = AF_INET6;
    nd->ndm_ifindex     = 0;
    nd->ndm_state       = (NUD_INCOMPLETE | NUD_REACHABLE | NUD_STALE | NUD_PROBE | NUD_DELAY
                                       | NUD_FAILED | NUD_PERMANENT | NUD_NOARP);
    nd->ndm_flags       = 0;
    nd->ndm_type        = 0;

    // send Netlink Msg

    struct sockaddr_nl sa;
    struct iovec iov = {(void*) nl, nl->nlmsg_len};
    struct msghdr msg = {(void*)& sa, sizeof(sa), &iov, 1, NULL, 0, 0};
    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    nl->nlmsg_seq = ++sequence_number;

    int ret = sendmsg(neighTableFd, &msg, 0);
    if(ret < 0)
    {
        cout << "sendmsg failed. err:" << errno
                << " errStr:" << std::strerror(errno));
        return false;
    }
    cout << << neighTableFd << " seqNum:" << sequence_number);
    ....
}

3. Sepreate thread to monitor fd.
void ipv6::NeighCacheMonitor::Run()
{
    while(1)
    {
        struct timeval tv;
        tv.tv_sec = 60;
        tv.tv_usec = 0;
        fd_set rfds;

        FD_ZERO(&rfds);
        FD_SET(neighTableFd, &rfds);

        int rv = select(neighTableFd, &rfds, NULL, NULL, &tv);
        if(rv < 0)
        {
            // Error Handling
        }

        if(FD_ISSET(neighTableFd, &rfds))
        {
            recvNLMsg(neighTableFd);
        }
    }
}

bool ipv6::NeighCacheMonitor::recvNLMsg(int fd)
{
    int len;
    char recvBuffer[4096];
    struct iovec iovRecv = {recvBuffer, sizeof(recvBuffer)};
    struct sockaddr_nl recvSaNl;
    struct msghdr recvMsgHdr;
    struct nlmsghdr* recvNlMsgHdr = NULL;

    recvMsgHdr.msg_name = (void*)& recvSaNl;
    recvMsgHdr.msg_namelen = sizeof(recvSaNl);
    recvMsgHdr.msg_iov = &iovRecv;
    recvMsgHdr.msg_iovlen = 1;
    recvMsgHdr.msg_control = NULL;
    recvMsgHdr.msg_controllen = 0;
    recvMsgHdr.msg_flags = 0;


    struct ndmsg* neigh = (struct ndmsg*) NLMSG_DATA(nlMsgHdrPtr);
    int length = nlMsgHdrPtr->nlmsg_len - NLMSG_LENGTH(sizeof(*neigh));
    if(length < 0)
    {
        cout "Invalid NLMsg length:" << length);
        return false;
    }
    len = recvmsg(fd, &recvMsgHdr, 0);
    . . . .
    HandleNeighMsg(recvNlMsgHdr);
}

HandleNeighMsg()
{
    cout << ": NeighMsgType: " << nlMsgHdrPtr->nlmsg_type << " NeighState: " << neigh->ndm_state;
    if(NUD_INCOMPLETE == nlMsgHdrPtr->nlmsg_type)
    {
        // Handle INCOMPLETE msg
    }
}
 
Last edited:


Your HandleNeighMessage method looks incorrect to me.
NUD_INCOMPLETE is a bit-mask in ndm_state.
In this line:
C++:
if(NUD_INCOMPLETE == nlMsgHdrPtr->nlmsg_type)
You’re checking it against nlmsg_type.
Unless I’m reading the documentation incorrectly, you need to check whether the state has the NUD_INCOMPLETE bit-flag set. So I think you need to be doing something like this:
C++:
if(nlMsgHdrPtr->nlmsg_state | NUD_COMPLETE)
{
    // Handle INCOMPLETE msg
}

Also, for future reference, please use code tags to enclose your code. It makes the code a lot more readable!
 
Last edited:

Staff online


Top