KD-Project_2: kernel module sk_buff send packet

Linux kernel would be huge without module support. With modules, we are able to add a code that runs in kernel space to extend the functionality. In this post will present the simple Loadable Kernel Module (LKM) that sends ethernet link layer frame (sent on broadcast address) which carries IP packet with UDP payload. We are currently running the 4.4.0-116-generic kernel. The full code you may find in the github repo: OPEN_ME.

The figure below shows the result of the networking LKM hello world: the packet, captured by wireshark contains the “hello world” message 🙂 

We are using VM with Ubuntu, thus to update we use the next command:

We are using VM with Ubuntu, thus to update we use the next command:

We need linux headers to build kernel code, thus we will install them

The Makefile is presented below. It will compile your lkm.c file to get kernel object.

Init function that is executed after LKM is loaded is presented below. We are setting the dst link layer address to broadcast and we send on the enp0s3 interface specific to ubuntu.
You could find your interfaces by typing “ip a sh” command. Also, we set the IP protocol to be used when building the packet. Finally, the init function calls “send_my” func that is responsible for the building of the packet and in the end prints “hello” message to the “/var/log/kernel.log”.

At the beginning of the “send_my” function we set up the src/dst IP addresses and filling the UDP payload. We define the lengths of UDP header, IP header, UDP payload and IP payload.

The next code snippet allocates a network buffer with Ethernet header + IP header + UDP header + UDP payload. We set the device in the skb_buff and define the packet type. Also we are allocating some space in the HEAD room for the ETH+IP+UDP headers. skb_reserve increase the headroom of skb by reducing the tail room.

This snippet of the code is actually put “hello world” in the DATA room of the sk_buff:

The next step is to add UDP header. To do that we  adjust the HEAD/DATA room with skb_push function. Here we set the len: UDP header+payload and give the ports:

Further, we add IP header where we describe the version, IP header+IP payload length (i.e. UDPh+UDPpayload). We set the Time To Live, source, destination addresses and protocol as a payload in the IP.

The pre-final steps are:

  • set src/dest link layer addresses:
  • set the IP in the skb->protocol;
  • disable frame checksum
  • set the type of the packet

And finally, when we have built the skb buffer, we send it to the queue of the device with dev_queue_xmit.

Thank you for reading.