title: Netlink socket show ip keywords: kernel,linux,netlink,socket,ip # Netlink show network interface ip's This example based on reading netlink socket and using kernel builtin netlink protocols. As base is used netlink example. __Makefile__ ```Makefile make: gcc netlink_show_ip.c -o netlink_show_ip ``` __netlink_show_ip.c__ ```c #include #include #include #include #include #include #define PAYLOAD_SIZE 1024 /* maximum payload size*/ #define NETLINK_PROTO 23 int main(int argc, char **argv) { struct sockaddr_nl src_addr; struct nlmsghdr *nlh; struct msghdr msg; struct iovec iov; int sock_fd; int ret; sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sock_fd < 0) { printf("socket creation for NETLINK failed...\n"); return -1; } close(sock_fd); return 0; } ``` ## Add socket configuration Here we configure netlink socket and send message to request ip addresses from NETLINK_ROUTE ```c ... int main(int argc, char **argv) { ... memset(&src_addr, 0, sizeof(src_addr)); src_addr.nl_family = AF_NETLINK; //bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));//??? // assemble the message according to the netlink protocol nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(PAYLOAD_SIZE)); memset(nlh, 0, NLMSG_SPACE(PAYLOAD_SIZE)); nlh->nlmsg_len = NLMSG_SPACE(PAYLOAD_SIZE); nlh->nlmsg_type = RTM_GETADDR; nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; struct ifaddrmsg *ifa; ifa = (struct ifaddrmsg*)NLMSG_DATA(nlh); ifa->ifa_family = AF_INET; // we only get ipv4 address here // prepare struct msghdr for sending. memset(&iov, 0, sizeof(iov)); iov.iov_base = (void *)nlh; iov.iov_len = nlh->nlmsg_len; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&src_addr; msg.msg_namelen = sizeof(src_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; // send netlink message to kernel. ret = sendmsg(sock_fd, &msg, 0); if (ret < 0) { printf("Can't send message to netlink socket\n"); } ... } ``` ## Receive and process netlink replies ```c #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ (nlh)->nlmsg_len <= (len)) ``` Message types ```c #define NLMSG_NOOP 0x1 /* Nothing. */ #define NLMSG_ERROR 0x2 /* Error */ #define NLMSG_DONE 0x3 /* End of a dump */ #define NLMSG_OVERRUN 0x4 /* Data lost */ ``` Definition of message rtnetlink types ```c RTM_NEWADDR = 20, #define RTM_NEWADDR RTM_NEWADDR ``` List of type of RTA types ```c enum { IFA_UNSPEC, IFA_ADDRESS, IFA_LOCAL, IFA_LABEL, IFA_BROADCAST, IFA_ANYCAST, IFA_CACHEINFO, IFA_MULTICAST, IFA_FLAGS, IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */ IFA_TARGET_NETNSID, IFA_PROTO, /* u8, address protocol */ __IFA_MAX, }; ``` Receiving netlink message from a ```c #include #include #include #include #include #include #include #include #include #include ... ... int main(){ ... do { ret = recvmsg(sock_fd, &msg_recv, 0); if (ret < 0) { printf("Can't receive reply message\n"); break; } if (ret==0) { printf("received 0 byte reply\n"); break; } ret_len = ret; nlh_recv = (struct nlmsghdr*)recv_buf; while (NLMSG_OK(nlh_recv, (uint32_t)ret_len) && (nlh_recv->nlmsg_type != NLMSG_DONE)) { printf("received message type %d\n", nlh_recv->nlmsg_type); if (nlh_recv->nlmsg_type == NLMSG_ERROR) { printf("Message error\n"); break; } if (nlh_recv->nlmsg_type == RTM_NEWADDR) { ... } nlh_recv = NLMSG_NEXT(nlh_recv, ret); } } while ((nl_msg_type != NLMSG_DONE) && (nl_msg_type != NLMSG_ERROR)); ... } ``` After message type is detected parse the RTNETLINK message ```c int main() { ... ifa_recv = (struct ifaddrmsg*)NLMSG_DATA(nlh_recv); int ifa_len = IFA_PAYLOAD(nlh_recv); rta = IFA_RTA(ifa_recv); printf("interface %s\n", if_indextoname(ifa_recv->ifa_index, ifname)); printf("prefix length %d\n", ifa_recv->ifa_prefixlen); while (RTA_OK(rta, ret_len)) { rta = RTA_NEXT(rta, ifa_len); char ip[INET6_ADDRSTRLEN]; //parse the message if (rta->rta_type == IFA_ADDRESS) { inet_ntop(ifa_recv->ifa_family, RTA_DATA(rta), ip, INET6_ADDRSTRLEN); printf("IFA_ADDRESS %s\n", ip); } if (rta->rta_type == IFA_LOCAL) { inet_ntop(ifa_recv->ifa_family, RTA_DATA(rta), ip, INET6_ADDRSTRLEN); printf("IFA_LOCAL %s\n", ip); } if (rta->rta_type == IFA_BROADCAST) { inet_ntop(ifa_recv->ifa_family, RTA_DATA(rta), ip, INET6_ADDRSTRLEN); printf("IFA_BROADCAST %s\n", ip); } } ... } ``` ## Build ```sh make ``` ## Run ```sh ./netlink_show_ip ``` Output looks like ```sh received message type 20 interface lo prefix length 8 IFA_LOCAL 127.0.0.1 received message type 20 interface enp0 prefix length 22 IFA_LOCAL 192.168.1.149 IFA_BROADCAST 192.168.1.255 ``` ## Final result __netlink_show_ip.c__ ```c #include #include #include #include #include #include #include #include #include #include #define PAYLOAD_SIZE 4096 /* maximum payload size*/ char recv_buf[4096]; int main(int argc, char **argv) { struct sockaddr_nl src_addr; struct nlmsghdr *nlh; struct nlmsghdr *nlh_recv; struct msghdr msg; struct msghdr msg_recv; struct iovec iov; struct iovec iov_recv; struct ifaddrmsg *ifa; struct ifaddrmsg *ifa_recv; struct rtattr *rta = NULL; int sock_fd; int ret; int ret_len; uint32_t nl_msg_type; char ifname[IF_NAMESIZE]; sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sock_fd < 0) { printf("socket creation for NETLINK failed...\n"); return -1; } memset(&src_addr, 0, sizeof(src_addr)); src_addr.nl_family = AF_NETLINK; bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));//??? // assemble the message according to the netlink protocol nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(PAYLOAD_SIZE)); memset(nlh, 0, NLMSG_SPACE(PAYLOAD_SIZE)); nlh->nlmsg_len = NLMSG_SPACE(PAYLOAD_SIZE); nlh->nlmsg_type = RTM_GETADDR; nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; ifa = (struct ifaddrmsg*)NLMSG_DATA(nlh); ifa->ifa_family = AF_INET; // we only get ipv4 address here // prepare struct msghdr for sending. memset(&iov, 0, sizeof(iov)); iov.iov_base = (void *)nlh; iov.iov_len = nlh->nlmsg_len; //struct msghdr msg = { src_addr, sizeof(*src_addr), &iov, 1, NULL, 0, 0 }; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&src_addr; msg.msg_namelen = sizeof(src_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; // send netlink message to kernel. ret = sendmsg(sock_fd, &msg, 0); if (ret < 0) { printf("Can't send message to netlink socket\n"); } //prepare to receive reply memset(&iov_recv, 0, sizeof(iov_recv)); iov_recv.iov_base = recv_buf; iov_recv.iov_len = PAYLOAD_SIZE; memset(&msg_recv, 0, sizeof(msg_recv)); msg_recv.msg_name = (void *)&src_addr; msg_recv.msg_namelen = sizeof(src_addr); msg_recv.msg_iov = &iov_recv; msg_recv.msg_iovlen = 1; do { ret = recvmsg(sock_fd, &msg_recv, 0); if (ret < 0) { printf("Can't receive reply message\n"); break; } if (ret==0) { printf("received 0 byte reply\n"); break; } ret_len = ret; nlh_recv = (struct nlmsghdr*)recv_buf; while (NLMSG_OK(nlh_recv, (uint32_t)ret_len) && (nlh_recv->nlmsg_type != NLMSG_DONE)) { printf("received message type %d\n", nlh_recv->nlmsg_type); if (nlh_recv->nlmsg_type == NLMSG_ERROR) { printf("Message error\n"); break; } if (nlh_recv->nlmsg_type == RTM_NEWADDR) { ifa_recv = (struct ifaddrmsg*)NLMSG_DATA(nlh_recv); int ifa_len = IFA_PAYLOAD(nlh_recv); rta = IFA_RTA(ifa_recv); printf("interface %s\n", if_indextoname(ifa_recv->ifa_index, ifname)); printf("prefix length %d\n", ifa_recv->ifa_prefixlen); while (RTA_OK(rta, ret_len)) { rta = RTA_NEXT(rta, ifa_len); char ip[INET6_ADDRSTRLEN]; //parse the message if (rta->rta_type == IFA_ADDRESS) { inet_ntop(ifa_recv->ifa_family, RTA_DATA(rta), ip, INET6_ADDRSTRLEN); printf("IFA_ADDRESS %s\n", ip); } if (rta->rta_type == IFA_LOCAL) { inet_ntop(ifa_recv->ifa_family, RTA_DATA(rta), ip, INET6_ADDRSTRLEN); printf("IFA_LOCAL %s\n", ip); } if (rta->rta_type == IFA_BROADCAST) { inet_ntop(ifa_recv->ifa_family, RTA_DATA(rta), ip, INET6_ADDRSTRLEN); printf("IFA_BROADCAST %s\n", ip); } } } nlh_recv = NLMSG_NEXT(nlh_recv, ret); } } while ((nl_msg_type != NLMSG_DONE) && (nl_msg_type != NLMSG_ERROR)); close(sock_fd); return 0; } ``` ## Links 1. [/notes/kernel/netlink_socket.md](/notes/kernel/netlink_socket.md) 1. https://github.com/d0u9/examples/blob/master/C/netlink/ip_show.c 2. https://gist.github.com/luohao-brian/7535fa346f37450137e5db45cd793ace 3. https://github.com/mwarning/netlink-examples/tree/master 4. https://elixir.bootlin.com/linux/v6.6.20/source/include/uapi/linux/rtnetlink.h#L42 5. https://elixir.bootlin.com/linux/v6.6.20/source/include/uapi/linux/netlink.h#L100