public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* Rtnetlink GETADDR request for 1 specific interface only (by ID)
@ 2024-05-16  9:19 Alexander Sergeev
  2024-05-16 11:19 ` Greg KH
  0 siblings, 1 reply; 3+ messages in thread
From: Alexander Sergeev @ 2024-05-16  9:19 UTC (permalink / raw)
  To: stable@vger.kernel.org; +Cc: regressions@lists.linux.dev


[-- Attachment #1.1: Type: text/plain, Size: 1679 bytes --]

Good morning!

Recently, I have found an issue with `rtnetlink` library that seems to be not intended and/or documented. I have asked about it several times, including here and it was also reported here. Neither in related RFC document nor in rtnetlink manuals the issue is described or mentioned.

In a few words, the issue is: for some reason, rtnetlink GETADDR request works only with NLM_F_ROOT or NLM_F_DUMP flags. Consequently, for instance, filtering by ifa_index field, that would *theoretically* according to docs, allow us to receive address info for 1 specific interface only (by ID) , is not possible. For comparison, similar functionality to GETLINK request (getting information about exactly 1 link by index) is indeed very possible. Instead of the expected output (information about 1 interface only), what is returned is an error message with errno -95, which, as I suppose, can be read as "operation not permitted".

To this email, I attach a small C file illustrating my issue. Feel free to change IFACE_ID define for ID of any network interface present in your system. It illustrates the error.

Please, let me know what you think about this issue. Am I missing something or does it really needs fixing or at least documenting?
Best regards,
Aleksandr Sergeev.

P.S. I have been told that this issue probably won't be addressed, because it "can easily be fixed in user space", however I believe in Linux kernel maintainers team dedication for clear, well-documented and bug-free code; so if this issue is not hard to fix, I would suggest addressing it at least in docs. If it can be useful, I would be more than grateful to provide my help with it.

[-- Attachment #1.2: Type: text/html, Size: 2402 bytes --]

[-- Attachment #2: main.c --]
[-- Type: application/octet-stream, Size: 2471 bytes --]

#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if_addr.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#define IFACE_ID 3
#define DATA_LENGTH 32768

struct packet {
    struct nlmsghdr hdr;
    struct ifaddrmsg msg;
};


void generate_address_request(struct packet* pack, int interface_id) {
    memset(pack, 0, sizeof(struct packet));
    pack->hdr.nlmsg_len = sizeof(struct packet);
    pack->hdr.nlmsg_type = RTM_GETADDR;
    pack->hdr.nlmsg_flags = NLM_F_REQUEST;
    pack->msg.ifa_index = interface_id;  // This gets ignored, why?
}

void parse_all_packets(char* messages_bytes, int total_length) {
    int index = 0, cursor = 0;
    while (cursor < total_length) {
        struct nlmsghdr* header = (struct nlmsghdr*) (messages_bytes + cursor);
        if (header->nlmsg_type == NLMSG_ERROR) {
            int* errnumber = (int*) (messages_bytes + cursor + sizeof(struct nlmsghdr));
            printf("Couldn't parse message #%d, errno: %d!\n", index, *errnumber);
        } else if (header->nlmsg_type == NLMSG_DONE) {
            printf("Message #%d, was the last one!\n", index);
            continue;
        } else {
            struct ifaddrmsg* message = (struct ifaddrmsg*) (messages_bytes + cursor + sizeof(struct nlmsghdr));
            printf("Message #%d contains interface #%d data, e.g. prefixlen: %d!\n", index, message->ifa_index, message->ifa_prefixlen);
        }
        cursor += header->nlmsg_len;
        index++;
    }
}

int main() {
    struct sockaddr_nl addr;
    memset(&addr, 0, sizeof(struct sockaddr_nl));
    addr.nl_family = AF_NETLINK;

    int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (sock == -1) {
        printf("Couldn't create netlink socket, errno: %d!\n", errno);
        exit(1);
    }

    int err = bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_nl));
    if (err != 0) {
        printf("Couldn't bind netlink socket, errno: %d!\n", errno);
        exit(1);
    }

    socklen_t len =  sizeof(struct sockaddr_nl);
    getsockname(sock, (struct sockaddr *) &addr, &len);

    struct packet pack;
    generate_address_request(&pack, IFACE_ID);
    write(sock, &pack, sizeof(struct packet));

    char buf[DATA_LENGTH];
    memset(buf, 0, DATA_LENGTH);
    int response_len = read(sock, buf, (socklen_t) DATA_LENGTH);
    parse_all_packets(buf, response_len);
}

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-05-16 12:07 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-16  9:19 Rtnetlink GETADDR request for 1 specific interface only (by ID) Alexander Sergeev
2024-05-16 11:19 ` Greg KH
     [not found]   ` <2c63357c6f3220819739d293c9a25f1f-1715860234@onmail.com>
2024-05-16 12:07     ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox