Skip to content

Instantly share code, notes, and snippets.

@Elecon-rou
Created January 26, 2017 22:32
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Elecon-rou/a74da272f620e0ac672114488db3f8aa to your computer and use it in GitHub Desktop.
Save Elecon-rou/a74da272f620e0ac672114488db3f8aa to your computer and use it in GitHub Desktop.
List all network interfaces with netlink
#include <stdio.h>
#include <unistd.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#define BUF_SIZE 8192
int fd;
int b;
int msg_len;
int attr_len;
char buf[BUF_SIZE];
struct sockaddr_nl kernel;
struct sockaddr_nl local;
struct msghdr msg;
struct iovec iov;
struct nlmsghdr *nlmsg_ptr;
struct ifinfomsg *ifi_ptr;
struct rtattr *attr_ptr;
struct nl_req_s
{
struct nlmsghdr hdr;
struct rtgenmsg gen;
};
typedef struct nl_req_s nl_req_t;
nl_req_t req;
int main()
{
memset(&kernel, 0, sizeof(kernel));
memset(&local, 0, sizeof(local));
memset(&msg, 0, sizeof(msg));
memset(&req, 0, sizeof(req));
kernel.nl_family = AF_NETLINK;
local.nl_family = AF_NETLINK;
local.nl_pid = getpid();
local.nl_groups = 0;
req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.hdr.nlmsg_type = RTM_GETLINK;
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
req.hdr.nlmsg_pid = getpid();
req.hdr.nlmsg_seq = 1;
req.gen.rtgen_family = AF_PACKET;
iov.iov_base = &req;
iov.iov_len = req.hdr.nlmsg_len;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_name = &kernel;
msg.msg_namelen = sizeof(kernel);
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) return -1;
b = bind(fd, (struct sockaddr *)&local, sizeof(local));
if (b < 0) return -2;
sendmsg(fd, (struct msghdr *)&msg, 0);
memset(&iov, 0, sizeof(iov));
iov.iov_base = buf;
iov.iov_len = BUF_SIZE;
msg_len = recvmsg(fd, &msg, 0);
nlmsg_ptr = (struct nlmsghdr *)buf;
while(NLMSG_OK(nlmsg_ptr, msg_len))
{
if(nlmsg_ptr->nlmsg_type != RTM_NEWLINK) continue;
ifi_ptr = NLMSG_DATA(nlmsg_ptr);
attr_ptr = IFLA_RTA(ifi_ptr);
attr_len = nlmsg_ptr->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi_ptr));
while(RTA_OK(attr_ptr, attr_len))
{
if(attr_ptr->rta_type == IFLA_IFNAME) printf("%s\n", (char *)RTA_DATA(attr_ptr));
attr_ptr = RTA_NEXT(attr_ptr, attr_len);
}
nlmsg_ptr = NLMSG_NEXT(nlmsg_ptr, msg_len);
}
}
@legale
Copy link

legale commented Sep 19, 2022

Not bad. Very clear code. But there is an error. You are receiving only 1 netlink message. So not all the interfaces are present.
you need another cycle over recvmsg()

while(1){
msg_len = recvmsg();
if(msg_len < 0) break;
nlmsg_ptr = (struct nlmsghdr *)iov.iov_base;
if(nlmsg_ptr->nlmsg_type == NLMSG_DONE) break;
....
}

Something like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment