如何在内核空间追加数据包?

我试图从内核空间附加一些数据包。 我有一个回声客户端和服务器。 我input如下命令行:./client“message”,服务器只是回显。 该服务器运行./server。

现在,客户端和服务器在两台不同的机器上(可能是虚拟机)。 我正在编写一个在客户机上运行的内核模块。 它的工作是在信息包出去之后在“消息”之后附加“12345”。 我正在呈现下面的代码。

/* * This is ibss_obsf_cat.c */ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/netfilter.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include <linux/udp.h> #include <linux/ip.h> #undef __KERNEL__ #include <linux/netfilter_ipv4.h> #define __KERNEL__ /* * Function prototypes ... */ static unsigned int cat_obsf_begin (unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)); static void hex_dump (char str[], int len) { } /* * struct nf_hook_ops instance initialization */ static struct nf_hook_ops cat_obsf_ops __read_mostly = { .pf = NFPROTO_IPV4, .priority = 1, .hooknum = NF_IP_POST_ROUTING, .hook = cat_obsf_begin, }; /* * Module init and exit functions. * No need to worry about that. */ static int __init cat_obsf_init (void) { printk(KERN_ALERT "cat_obsf module started...\n"); return nf_register_hook(&cat_obsf_ops); } static void __exit cat_obsf_exit (void) { nf_unregister_hook(&cat_obsf_ops); printk(KERN_ALERT "cat_obsf module stopped...\n"); } /* * Modification of the code begins here. * Here are all the functions and other things. */ static unsigned int cat_obsf_begin (unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct iphdr *iph; struct udphdr *udph; unsigned char *data; unsigned char dt[] = "12345"; unsigned char *tmp; unsigned char *ptr; int i, j, len; if (skb){ iph = ip_hdr(skb); if (iph && iph->protocol && (iph->protocol == IPPROTO_UDP)){ udph = (struct udphdr *) ((__u32 *)iph + iph->ihl); data = (char *)udph + 8; if(ntohs(udph->dest) == 6000){ for (i=0; data[i]; i++); len = i; //printk(KERN_ALERT "\nData length without skb: %d", len); //printk(KERN_ALERT "Data is: %s", data); //printk(KERN_ALERT "dt size: %lu", sizeof(dt)); //printk(KERN_ALERT "skb->len: %d", skb->len); tmp = kmalloc(200*sizeof(char), GFP_KERNEL); memcpy(tmp, data, len); ptr = tmp + len; memcpy(ptr, dt, sizeof(dt)); printk(KERN_ALERT "tmp: %s", tmp); printk(KERN_ALERT "skb->tail: %d", skb->tail); //skb_put(skb, sizeof(dt)); printk(KERN_ALERT "skb->end: %d", skb->end); printk(KERN_ALERT "skb->tail: %d", skb->tail); printk(KERN_ALERT "skb->tail(int): %d", (unsigned int)skb->tail); //memset(data, 0, len + sizeof(dt)); //memcpy(data, tmp, len + sizeof(dt)); //skb_add_data(skb, tmp, len+sizeof(dt)); printk(KERN_ALERT "Now data is: %s", data); for(i=0; data[i]; i++); printk(KERN_ALERT "data length: %d", i); kfree(tmp); } } } return NF_ACCEPT; } /* * Nothing to be touched hereafter */ module_init(cat_obsf_init); module_exit(cat_obsf_exit); MODULE_AUTHOR("Rifat"); MODULE_DESCRIPTION("Module for packet mangling"); MODULE_LICENSE("GPL"); 

在从内核空间发出客户机时,我想让“消息”成为“message12345”。 因此,服务器将得到“message12345”并回显,客户端将只读“message12345”但我有问题与skb_put()和skb_add_data()函数。 我不明白我犯了什么错误。 如果有人能帮助我的代码,我将非常感激。 提前致谢。 为了方便,我也给了Makefile。 这是为了分发内核,而不是为了构build内核。

 #If KERNELRELEASE is defined, we've been invoked from the #kernel build system and use its language ifneq ($(KERNELRELEASE),) obj-m := ibss_obsf_cat.o #Otherwise we were called directly from the command #line; invoke the kernel build system. else KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif 

现在我确信skb-> end – skb-> tail太小,我不得不在内核空间中创build新的数据包。 我已经使用alloc_skb()skb_reserve()skb_header_pointer()和其他有用的skb函数来创build一个新的skb,但是我正在运行的想法是如何路由在数据包streampath中新创build的数据包。 如何使用
ip_route_me_harder()我在xtables-addons软件包中寻找build议,但是它们使用的函数与linux内核中的不同。 任何build议是受欢迎的。

Solutions Collecting From Web of "如何在内核空间追加数据包?"

大约一年前,对于内核2.6.26,我是这样做的:

 // Do we need extra space? if(len - skb_tailroom(skb) > 0){ // Expand skb tail until we have enough room for the extra data if (pskb_expand_head(skb, 0, extra_data_len - skb_tailroom(skb), GFP_ATOMIC)) { // allocation failed. Do whatever you need to do } // Allocation succeeded // Reserve space in skb and return the starting point your_favourite_structure* ptr = (your_favourite_structure*) skb_push(skb, sizeof(*ptr)); // Now either set each field of your structure or memcpy into it. // Remember you can use a char* } 

别忘了:

  • 重新计算UDP校验和,因为您更改了传输数据中的数据。

  • 因为您已将数据添加到数据包,请更改ip标头中的字段tot_len (总长度)。

  • 重新计算IP标头校验和,因为您更改了tot_len字段。

额外说明 :这只是一个简单的事情。 我在你的代码中看到你正在分配tmp作为一个200字节的数组,并用它来存储你的消息的数据。 如果发送更大的数据包,则由于内存溢出太痛苦,内核崩溃时您将很难调试。

我已经解决了这个问题。 这是微不足道的。 而我所要做的就是发布我的代码,以备将来参考和讨论。

 #include <linux/kernel.h> #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netfilter.h> #include <linux/netdevice.h> #include <linux/ip.h> #include <linux/udp.h> #include <linux/mm.h> #include <linux/err.h> #include <linux/crypto.h> #include <linux/init.h> #include <linux/crypto.h> #include <linux/scatterlist.h> #include <net/ip.h> #include <net/udp.h> #include <net/route.h> #undef __KERNEL__ #include <linux/netfilter_ipv4.h> #define __KERNEL__ #define IP_HDR_LEN 20 #define UDP_HDR_LEN 8 #define TOT_HDR_LEN 28 static unsigned int pkt_mangle_begin(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)); static struct nf_hook_ops pkt_mangle_ops __read_mostly = { .pf = NFPROTO_IPV4, .priority = 1, .hooknum = NF_IP_LOCAL_OUT, .hook = pkt_mangle_begin, }; static int __init pkt_mangle_init(void) { printk(KERN_ALERT "\npkt_mangle module started ..."); return nf_register_hook(&pkt_mangle_ops); } static void __exit pkt_mangle_exit(void) { nf_unregister_hook(&pkt_mangle_ops); printk(KERN_ALERT "pkt_mangle module stopped ..."); } static unsigned int pkt_mangle_begin (unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct iphdr *iph; struct udphdr *udph; unsigned char *data; unsigned int data_len; unsigned char extra_data[] = "12345"; unsigned char *temp; unsigned int extra_data_len; unsigned int tot_data_len; unsigned int i; __u16 dst_port, src_port; if (skb) { iph = (struct iphdr *) skb_header_pointer (skb, 0, 0, NULL); if (iph && iph->protocol &&(iph->protocol == IPPROTO_UDP)) { udph = (struct udphdr *) skb_header_pointer (skb, IP_HDR_LEN, 0, NULL); src_port = ntohs (udph->source); dst_port = ntohs (udph->dest); if (src_port == 6000) { printk(KERN_ALERT "UDP packet goes out"); data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL); data_len = skb->len - TOT_HDR_LEN; temp = kmalloc(512 * sizeof(char), GFP_ATOMIC); memcpy(temp, data, data_len); unsigned char *ptr = temp + data_len - 1; extra_data_len = sizeof(extra_data); memcpy(ptr, extra_data, extra_data_len); tot_data_len = data_len + extra_data_len - 1; skb_put(skb, extra_data_len - 1); memcpy(data, temp, tot_data_len); /* Manipulating necessary header fields */ iph->tot_len = htons(tot_data_len + TOT_HDR_LEN); udph->len = htons(tot_data_len + UDP_HDR_LEN); /* Calculation of IP header checksum */ iph->check = 0; ip_send_check (iph); /* Calculation of UDP checksum */ udph->check = 0; int offset = skb_transport_offset(skb); int len = skb->len - offset; udph->check = ~csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_UDP, 0); } } } return NF_ACCEPT; } module_init(pkt_mangle_init); module_exit(pkt_mangle_exit); MODULE_AUTHOR("Rifat Rahman Ovi: <rifatrahmanovi@gmail.com>"); MODULE_DESCRIPTION("Outward Packet Mangling and Decryption in coreel Space"); MODULE_LICENSE("GPL"); 

这里的事情是,我忘了更新长度字段,忘了更新校验和。 现在,如果我在这里正确地提交代码,一切都应该顺利。 还有一些其他的帮手功能,这里不包括。