|Network| Build a kernel module and send my packet

I refer an article KD-Project_2: kernel module sk_buff send packet and make a test.

sudo apt update

Install kernel header:

sudo apt install linux-headers-$(uname -r)

Makefile

obj-m+=zztest.o
all:
	make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
	make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean

zztest.c ,
orignal author: Dmytro Shytyi
I modified some overflow in memcpy.

#include <linux/init.h>
#include <linux/module.h>           // for loading zztest into the kernel
#include <linux/kernel.h> 
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fcntl.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h> 
#include <linux/etherdevice.h>
#include <linux/netdevice.h> 
#include <linux/etherdevice.h>
//#include <linux/string.h>
#include <linux/ip.h> 
#include <linux/udp.h>
MODULE_LICENSE("GPL");              ///< The license type -- this affects runtime behavior
MODULE_AUTHOR("Dmytro Shytyi");      ///< The author -- visible when you use modinfo
MODULE_DESCRIPTION("A simple linux kernel module - send hello world packet.");  ///< The description -- see modinfo
MODULE_VERSION("0.1");              ///< The version of the module
 
 
static int send_my(struct net_device* dev, uint8_t dest_addr[ETH_ALEN], uint16_t proto);

static int __init helloZZ_init(void){
	uint16_t proto;
	static char addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
	uint8_t dest_addr[ETH_ALEN];
	struct net_device *enp0s3;
	enp0s3 = dev_get_by_name(&init_net,"enp0s3");
	memcpy(dest_addr, addr, sizeof(addr));//ETH_ALEN);
	proto = ETH_P_IP;
	send_my(enp0s3,dest_addr,proto);
	printk(KERN_INFO "Hello from the  LKM!\n" );
   return 0;
}

unsigned int inet_addr(char *str)
{
    int a, b, c, d;
    char arr[4];
    sscanf(str, "%d.%d.%d.%d", &a, &b, &c, &d);
    arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d;
    return *(unsigned int *)arr;
}

int
send_my(struct net_device* dev, uint8_t dest_addr[ETH_ALEN], uint16_t proto)
{
  int            ret;
  unsigned char* data;
  
  char *srcIP = "192.168.0.1";
  char *dstIP = "192.168.0.2";
  char *hello_world = ">>> KERNEL Zanna <<<";
  int data_len = 51;

  int udp_header_len = 8;
  int udp_payload_len = data_len;
  int udp_total_len = udp_header_len+udp_payload_len;

  int ip_header_len = 20;
  int ip_payload_len = udp_total_len;
  int ip_total_len = ip_header_len + ip_payload_len;

/* skb */
  struct sk_buff* skb = alloc_skb(ETH_HLEN+ip_total_len, GFP_ATOMIC);//allocate a network buffer
  skb->dev = dev;
  skb->pkt_type = PACKET_OUTGOING;
  skb_reserve(skb, ETH_HLEN+ip_header_len+udp_header_len);//adjust headroom
/* allocate space to data and write it */
  data = skb_put(skb,udp_payload_len);
  memcpy(data, hello_world, sizeof(hello_world);//)data_len);
/* UDP header */
  struct udphdr* uh = (struct udphdr*)skb_push(skb,udp_header_len);
  uh->len = htons(udp_total_len);
  uh->source = htons(15934);
  uh->dest = htons(15904);

/* IP header */
  struct iphdr* iph = (struct iphdr*)skb_push(skb,ip_header_len);
  iph->ihl = ip_header_len/4;//4*5=20 ip_header_len
  iph->version = 4; // IPv4u
  iph->tos = 0; 
  iph->tot_len=htons(ip_total_len); 
  iph->frag_off = 0; 
  iph->ttl = 64; // Set a TTL.
  iph->protocol = IPPROTO_UDP; //  protocol.
  iph->check = 0; 
  iph->saddr = inet_addr(srcIP);
  iph->daddr = inet_addr(dstIP);

  /*changing Mac address */
  struct ethhdr* eth = (struct ethhdr*)skb_push(skb, sizeof (struct ethhdr));//add data to the start of a buffer
  skb->protocol = eth->h_proto = htons(proto);
  skb->no_fcs = 1;
  memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
  memcpy(eth->h_dest, dest_addr, ETH_ALEN);
 

  skb->pkt_type = PACKET_OUTGOING;
  ret = dev_queue_xmit(skb);
  return 1;
} 

static void __exit helloZZ_exit(void){
   printk(KERN_INFO "Goodbye from LKM!\n");
}
 
module_init(helloZZ_init);
module_exit(helloZZ_exit);

Build

make

Import module

sudo insmod zztest.ko

Remove module

sudo rmmod zztest.ko



Other references:
https://stackoverflow.com/questions/29553990/print-tcp-packet-data
https://pypi.org/project/NetfilterQueue/

https://stackoverflow.com/questions/34866677/libnetfilter-queue-why-cant-i-see-the-tcp-payload-of-packets-from-nfq-get-payl