summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArturs Artamonovs <dos21h@gmail.com>2024-04-09 06:57:54 +0100
committerArturs Artamonovs <dos21h@gmail.com>2024-04-09 06:57:54 +0100
commit46336b7a31fb14e22fe9c270f5ba50b21a8909a5 (patch)
treea60d6032af2f5d7cea66cfba8edcb7b98ebf5e5f
parent43c513ea604c77e71333d8307bdb9b710b091721 (diff)
downloadmd-content-46336b7a31fb14e22fe9c270f5ba50b21a8909a5.tar.gz
md-content-46336b7a31fb14e22fe9c270f5ba50b21a8909a5.zip
Add netlink socket
-rw-r--r--md/notes/kernel/netlink_show_ip.md423
1 files changed, 423 insertions, 0 deletions
diff --git a/md/notes/kernel/netlink_show_ip.md b/md/notes/kernel/netlink_show_ip.md
new file mode 100644
index 0000000..87f0b83
--- /dev/null
+++ b/md/notes/kernel/netlink_show_ip.md
@@ -0,0 +1,423 @@
+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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+...
+...
+
+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
+
+```
+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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#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
+