summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArturs Artamonovs <dos21h@gmail.com>2024-04-03 10:24:20 +0100
committerArturs Artamonovs <dos21h@gmail.com>2024-04-03 10:24:20 +0100
commit91488a98f3e3d222dab31358ef2acb94f48c6e68 (patch)
tree8603019e60a2874d042098e138e68cf4e89b0bbd
parente10880e595275651d62548a5e0388540ba697c5e (diff)
downloadmd-content-91488a98f3e3d222dab31358ef2acb94f48c6e68.tar.gz
md-content-91488a98f3e3d222dab31358ef2acb94f48c6e68.zip
Add netlink
-rw-r--r--md/notes/kernel/netlink_socket.md322
-rw-r--r--md/notes/kernel/topics.md12
2 files changed, 331 insertions, 3 deletions
diff --git a/md/notes/kernel/netlink_socket.md b/md/notes/kernel/netlink_socket.md
new file mode 100644
index 0000000..01e9043
--- /dev/null
+++ b/md/notes/kernel/netlink_socket.md
@@ -0,0 +1,322 @@
+title: Netlink socket
+keywords: kernel,linux,netlink,socket
+
+# Kernel compile "Hello world"
+
+Compile minimal linux kernel module.
+
+## Files
+
+You need to create to files __Makefile__ and __hello_world.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 <linux/module.h> /* Needed by all modules */
+#include <linux/kernel.h>
+
+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 <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+
+
+#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<msg_len; i++) {
+ if ((msg[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 <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 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
+
diff --git a/md/notes/kernel/topics.md b/md/notes/kernel/topics.md
index be7f723..d955193 100644
--- a/md/notes/kernel/topics.md
+++ b/md/notes/kernel/topics.md
@@ -17,21 +17,23 @@ kernel API's.
[Sysfs](/notes/kernel/create_sysfs_entry.md)
[Procfs](/notes/kernel/create_procfs_entry.md)
[User mode helpers](/notes/kernel/usermode_helper.md)
-
+<!--[!IOCTL driver](/notes/kernel/ioctl_driver.md) -->
+<!--[!IRQ handler](/notes/kernel/irq_handler.md) -->
<!-- Ramfs -->
<!-- Write files to user space -->
<!-- Read files from user space -->
<!-- Create character device -->
<!-- Create netfilter firewall -->
<!-- DMA programming -->
-<!-- IOCTL -->
+
### Intermediate
[Kernel /dev/hwrng](/writeup/kernel_dev_hwrng.md)
+[Netlink socket](/notes/kernel/netlink_socket.md)
<!-- Create syscall -->
-<!-- Netlink -->
+
<!-- Dummy I2C driver -->
<!-- Dummy SPI driver -->
<!-- Create ADC driver -->
@@ -45,3 +47,7 @@ kernel API's.
<!-- Virtual Pinctrl driver -->
<!-- Create key logger -->
<!-- Create device tree entry -->
+
+### Kernel userspace
+
+