3

I have a small test code that checks for eth interface up/down events from the RTNLGRP_LINKmulticast group, but unfortunately, I'm always getting the RTM_NEWLINK event even when I unplug and replug the network cable. I expect RTM_DELLINK when I unplug the cable and RTM_NEWLINK when the cable is connected. I'm using libnl-3.4.0 library.

can anyone point out what I'm doing wrong?

extern "C"
{
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <arpa/inet.h>
}

#include <iostream>

static int parseLink(struct nlmsghdr *hdr)
{
    struct ifinfomsg *iface = (struct ifinfomsg *)nlmsg_data(hdr);

    struct nlattr *attrs[IFLA_MAX + 1];

    if (nlmsg_parse(hdr, sizeof(struct ifinfomsg), attrs, IFLA_MAX, nullptr) < 0)
    {
        std::cerr << "problem parsing Netlink response" << std::endl;
        return -1;
    }

    if (attrs[IFLA_IFNAME] != nullptr)
    {
        if (hdr->nlmsg_type == RTM_NEWLINK)
        {
            std::cout << "Interface " << (char *)nla_data(attrs[IFLA_IFNAME]) << " added" << std::endl;
        }
        else if (hdr->nlmsg_type == RTM_DELLINK)
        {
            std::cout << "Interface " << (char *)nla_data(attrs[IFLA_IFNAME]) << " deleted" << std::endl;
        }
    }
    return 0;
}

static int receiveNewMsg(struct nl_msg *msg, void *arg)
{
    struct nlmsghdr *nlh = nlmsg_hdr(msg);
    int len = nlh->nlmsg_len;
    while (nlmsg_ok(nlh, len))
    {
        if (nlh->nlmsg_type != RTM_NEWLINK && nlh->nlmsg_type != RTM_DELLINK)
        {
            if (nlh->nlmsg_type == NLMSG_DONE)
            {
                std::cout << "message complete" << std::endl;
            }
            nlh = nlmsg_next(nlh, &len);
            continue;
        }
        if ((nlh->nlmsg_type == RTM_DELLINK) || (nlh->nlmsg_type == RTM_NEWLINK))
        {
            parseLink(nlh);
        }
        nlh = nlmsg_next(nlh, &len);
    }
    return 0;
}

int main(int argc, char const *argv[])
{
    struct nl_sock *sk;

    /* Allocate a new socket */
    sk = nl_socket_alloc();

    /*
    * Notifications do not use sequence numbers, disable sequence number checking.
    */
    nl_socket_disable_seq_check(sk);

    /*
    * Define a callback function, which will be called for each notification received
    */
    nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, receiveNewMsg, nullptr);
    nl_socket_modify_cb(sk, NL_CB_FINISH, NL_CB_CUSTOM, receiveNewMsg, nullptr);

    /* Connect to routing netlink protocol */
    nl_connect(sk, NETLINK_ROUTE);

    /* Subscribe to link notifications group */
    nl_socket_add_memberships(sk, RTNLGRP_LINK);

    /*
    * Start receiving messages. The function nl_recvmsgs_default() will block
    * until one or more netlink messages (notification) are received which
    * will be passed on to my_func().
    */

    while (1)
        nl_recvmsgs_default(sk);

    return 0;
}

CMakeLists.txt to compile the above code:

cmake_minimum_required(VERSION 3.10)

project(mptcpd VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

include_directories(/usr/include/libnl3/)

file(GLOB SOURCES
    *.h
    *.cpp
)

add_executable(${PROJECT_NAME} ${SOURCES})

target_link_libraries(${PROJECT_NAME} libnl-3.so)

Update: I thought it's something to do with the libnl library so I tried an example without libnl library but the thing is the same.

Here is the example I tried: http://olegkutkov.me/2018/02/14/monitoring-linux-networking-state-using-netlink/

Vencat
  • 1,272
  • 11
  • 36

0 Answers0