title: Netlink socket keywords: kernel,linux,netlink,socket # Kernel netlink socket As base start from minimal kernel module ## Files You need to create to files __Makefile__ and __netlink_socket.c__. __Makefile__ ```Makefile obj-m += netlink_socket.o KDIR ?= /lib/modules/$(shell uname -r)/build all: make -C $(KDIR) M=$(PWD) modules clean: make -C $(KDIR) M=$(PWD) clean ``` __netlink_socket.c__ ```c //http://www.tldp.org/LDP/lkmpg/2.4/html/c147.htm #include /* Needed by all modules */ #include int netlink_socket_init( void ) { printk(KERN_DEBUG "Netlink World!\n"); return 0; } void netlink_socket_exit( void ) { printk(KERN_DEBUG "Exit Netlink World!\n"); } module_init( netlink_socket_init ); module_exit( netlink_socket_exit ); MODULE_LICENSE("GPL"); ``` ## Add netlink basic structures ```c /* optional Netlink kernel configuration parameters */ struct netlink_kernel_cfg { unsigned int groups; unsigned int flags; void (*input)(struct sk_buff *skb); struct mutex *cb_mutex; int (*bind)(struct net *net, int group); void (*unbind)(struct net *net, int group); void (*release) (struct sock *sk, unsigned long *groups); }; ``` ```c ... #include #include #include #define NETLINK_NEW_SCK 23 //+1 from NETLINK_SMC struct sock *nlsk = NULL; static void netlink_receive(struct sk_buff *skb) { printk("Receive the message\n"); } struct netlink_kernel_cfg nlsk_cfg = { .input = netlink_receive, }; ... int netlink_socket_init( void ) { ... nlsk = netlink_kernel_create(&init_net, NETLINK_NEW_SCK, &nlsk_cfg); if(nlsk == NULL) { printk(KERN_INFO "error creating netlink socket...\n"); return -1; } ... } ... ``` ## Add recieve capability for netlink socket ```c /** * nlmsg_put - Add a new netlink message to an skb * @skb: socket buffer to store message in * @portid: netlink PORTID of requesting application * @seq: sequence number of message * @type: message type * @payload: length of message payload * @flags: message flags * * Returns NULL if the tailroom of the skb is insufficient to store * the message header and payload. */ static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int payload, int flags) ``` ```c static inline int nlmsg_unicast(struct sock *sk, struct sk_buff *skb, u32 portid); ``` The protocol number is choosen +1 after last one that is defined in netlink headers. Protocol number is 23. Protocol with just echo back what was sent. ```c ... static void netlink_receive(struct sk_buff *skb) { struct nlmsghdr *nlh; // Netlink message header int pid = 0; struct sk_buff *skb_out; char *msg = NULL; char msg_len = 0; int ret = 0; if (skb == NULL) { printk(KERN_ERR "%s: socket buffer is empty...\n", __FUNCTION__); return; } nlh = (struct nlmsghdr *)skb->data; pid = nlh->nlmsg_pid; msg_len = strlen(NLMSG_DATA(nlh)); msg = NLMSG_DATA(nlh); printk(KERN_INFO "Received pid: %d, msg: %s, len: %d\n", pid, msg, msg_len); // Create a new socket buffer with received message copied: skb_out = nlmsg_new(msg_len, 0); if (skb_out == NULL) { printk(KERN_ERR "%s: netlink new socket creation failed...\n", __FUNCTION__); return; } nlh = nlmsg_put(skb_out, 0, 0, 0, msg_len, 0); // flag 0, pid kernel 0, seq 0, payload msg_len, flags 0 strncpy(NLMSG_DATA(nlh), msg, msg_len); // Send back the message to app: ret = nlmsg_unicast(nlsk, skb_out, pid); if (ret < 0) { printk(KERN_ERR "%s: netlink unicast failed...\n", __FUNCTION__); return; } printk(KERN_INFO "%s: returned...", __FUNCTION__); } ... ``` Add to protocol capitalising lettes, so whats was received is sent back in capitalised letters. ```c for (int i=0;i= 'a') && (msg[i] <= 'z')) { msg[i] -= 0x20; } } ``` Add to module exit function socket release ```c void netlink_socket_exit( void ) { ... netlink_kernel_release(nlsk); ... } ``` ## Create userspace utility As netlink is communication interface between kernel and userspace there is possible to create utility that connects and interacts with netlink socket. ```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 sockaddr_nl dest_addr; struct nlmsghdr *nlh; struct msghdr msg; struct iovec iov; int sock_fd; int ret; sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_PROTO); 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; src_addr.nl_pid = getpid(); bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr)); nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(PAYLOAD_SIZE)); memset(nlh, 0, NLMSG_SPACE(PAYLOAD_SIZE)); nlh->nlmsg_len = NLMSG_SPACE(PAYLOAD_SIZE); nlh->nlmsg_pid = getpid(); nlh->nlmsg_flags = 0; strcpy(NLMSG_DATA(nlh), "Test test Test!"); memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.nl_family = AF_NETLINK; dest_addr.nl_pid = 0; // Linux Kernel PID dest_addr.nl_groups = 0; 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 *)&dest_addr; msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; ret = sendmsg(sock_fd, &msg, 0); printf("Message sent, payload: %s\n", (char *)NLMSG_DATA(nlh)); // Clear netlink packet payload: memset(nlh, 0, NLMSG_SPACE(PAYLOAD_SIZE)); // Receive msg from kernel: ret = recvmsg(sock_fd, &msg, 0); printf("Message received, payload: %s\n", (char *)NLMSG_DATA(nlh)); close(sock_fd); return 0; } ``` Add to makefile step to compile userspace program ```makefile all: make -C $(KDIR) M=$(PWD) modules gcc netlink_connect.c -o netlink_connect ``` ## Compile Compile the module and userspace program ```sh make ``` ## Load module ```sh sudo insmod netlink_socket.ko ``` check that module is running ```sh lsmod | grep netlink ``` ## Unload module ```sh rmmod netlink_socket ``` ## Test Run userspace programm and receive back message with capitalised letters ```bash ./netlink_connect Message sent, payload: Test test Test! Message received, payload: TEST TEST TEST! ``` ## Links 1. [https://elixir.bootlin.com/linux/latest/source/include/linux/netlink.h](https://elixir.bootlin.com/linux/latest/source/include/linux/netlink.h) 2. https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/netlink.h#L52 3. https://gist.github.com/chrizchow/79c53514c80b5994f92f82523d54f67f 4. https://elixir.bootlin.com/linux/v6.6.20/source/include/linux/skbuff.h#L842 5. https://github.com/mwarning/netlink-examples/tree/master/multicast_example 6. https://github.com/d0u9/examples/tree/master/C/netlink