diff options
Diffstat (limited to 'md')
| -rw-r--r-- | md/notes/kernel/netlink_socket.md | 322 | ||||
| -rw-r--r-- | md/notes/kernel/topics.md | 12 | 
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 + +  | 
