Get list of network interfaces using rtnetlink sockets
/** * @file get_if_list.c * * @brief Print the list of network interfaces available on the system. * * The network interface list is obtained using rtnetlink sockets. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <asm/types.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #define IF_LIST_SIZE 10 static int32_t create_rtnetlink_sock(int32_t *sd); static int32_t send_if_list_req(int32_t sd); static int32_t recv_if_list_resp(int32_t sd, char iflist[IF_LIST_SIZE][IF_NAMESIZE]); int main(void) { char iflist[IF_LIST_SIZE][IF_NAMESIZE]; int32_t sd; int32_t ret; ret = create_rtnetlink_sock(&sd); if (ret == -1) { fprintf(stderr, "Unable to create rtnetlink socket.\n"); goto out1; } ret = send_if_list_req(sd); if (ret == -1) { fprintf(stderr, "Unable to send GET INTERFACE request.\n"); goto out2; } ret = recv_if_list_resp(sd, iflist); if (ret == -1) { fprintf(stderr, "Unable to receive INTERFACE list request.\n"); goto out2; } close(sd); exit(0); out2: close(sd); out1: exit(1); } /** * @brief Create a rtnetlink socket. * * @param[out] sd Will be filled with newly created socket's descriptor. * * @return 0 on success; -1 on failure. */ static int32_t create_rtnetlink_sock(int32_t *sd) { struct sockaddr_nl nl; int32_t ret; if (sd == NULL) { fprintf(stderr, "%s: Invalid arguments.\n", __func__); goto out1; } *sd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if (*sd == -1) { perror("socket"); goto out1; } memset(&nl, 0, sizeof(nl)); nl.nl_family = AF_NETLINK; ret = bind(*sd, (struct sockaddr *)&nl, sizeof(nl)); if (ret == -1) { perror("bind"); goto out2; } return 0; out2: close(*sd); out1: return -1; } /** * @brief Construct and send a request for obtaining the list of * network interfaces. * * @param[in] sd rtnetlink socket descriptor to be used for communication. * * @return 0 on success; -1 on failure. */ static int32_t send_if_list_req(int32_t sd) { struct { struct nlmsghdr nh; struct ifinfomsg ifinfomsg; } req; ssize_t ssize; memset(&req, 0, sizeof(req)); req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifinfomsg)); req.nh.nlmsg_type = RTM_GETLINK; req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; req.ifinfomsg.ifi_family = AF_UNSPEC; ssize = send(sd, &req, sizeof(req), 0); if (ssize == -1) { perror("send"); return -1; } return 0; } /** * @brief Receive and process the rtnetlink response (containing the list * of interfaces). * * @param[in] sd rtnetlink socket descriptor to be used for communication. * * @return 0 on success; -1 on failure. */ static int32_t recv_if_list_resp(int32_t sd, char iflist[IF_LIST_SIZE][IF_NAMESIZE]) { struct ifinfomsg *ifinfomsg; struct nlmsghdr *nh; struct nlmsgerr *nlme; struct rtattr *rta; struct { struct nlmsghdr nh; uint8_t payload[1024]; } resp; ssize_t ssize; int32_t len; int32_t attr_len; ssize = recv(sd, &resp, sizeof(resp), 0); if (ssize == -1) { perror("recv"); return -1; } nh = &(resp.nh); if (nh->nlmsg_type == NLMSG_ERROR) { nlme = NLMSG_DATA(nh); fprintf(stderr, "Got error %d.\n", nlme->error); return -1; } len = ssize; printf("Available interfaces:\n"); for (;NLMSG_OK(&(resp.nh), len); nh = NLMSG_NEXT(nh, len)) { ifinfomsg = NLMSG_DATA(nh); rta = IFLA_RTA(ifinfomsg); attr_len = IFLA_PAYLOAD(nh); for (; RTA_OK(rta, attr_len); rta = RTA_NEXT(rta, attr_len)) { if (rta->rta_type == IFLA_IFNAME) { printf("%s ", (char *)RTA_DATA(rta)); } } if (nh->nlmsg_type == NLMSG_DONE) { break; } } printf("\n"); return 0; }
Compile and run the program as shown below:
[mwnn@schumi rtnetlink]$ cc -g -Wall get_if_list.c -oget_if_list [mwnn@schumi rtnetlink]$ ./get_if_list Available interfaces: lo eth0
HTML generated by org-mode 7.3 in emacs 23
Strange I got only localhost iface
ReplyDeleteAvailable interfaces:
lo