当前位置: 首页 > 面试题库 >

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

党浩阔
2023-03-14
问题内容

我试图在内核空间的数据包上附加一些数据。我有一个回显客户端和服务器。我在命令行中键入:./client“
message”,服务器将其回显。服务器使用./server运行。

现在,客户端和服务器位于两台不同的计算机(可能是VM)上。我正在编写一个在客户端计算机上运行的内核模块。它的工作是在数据包离开机器时在“消息”之后附加“
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");

我希望从内核空间发送出客户端计算机时将“ message”设置为“ message12345”。这样服务器将获得“
message12345”并回显,而客户端将仅读取“
message12345”,但是我在使用skb_put()和skb_add_data()函数时遇到了麻烦。我不明白我犯了什么错误。如果有人可以帮助我编写代码,我将不胜感激。提前致谢。为了方便起见,我也提供Makefile。这是针对分发内核的,而不是针对构建内核的。

#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很小,我将不得不在内核空间中创建新的数据包。我已经使用alloc_skb()skb_reserve()skb_header_pointer()和其他有用的skb函数来创建新的skb,但我的想法已荡然无存,那就是如何在数据包流动路径中路由新创建的数据包。如何使用
ip_route_me_harder()我在xtables-addons包中寻找了建议,但是它们使用的功能不同于linux内核中的功能。任何建议都欢迎。


问题答案:

大约一年前,对于内核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校验和,因为您更改了传输数据中的数据。

  • 更改tot_lenip标头中的字段(总长度),因为您已向数据包中添加了数据。

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

附加说明
:这只是简单的事情。我在您的代码中看到您正在分配tmp一个200字节的数组,并使用该数组存储消息的数据。如果发送更大的数据包,将很难调试,因为由于内存溢出而导致的内核崩溃太痛苦了。



 类似资料:
  • 我试图通过循环元素,然后通过分页单击来获得链接列表。我不确定如何在熊猫数据帧中的每个循环经过下面显示的分页后追加,这样我就可以在循环之外调用数据帧来列出所有的链接。 它总是覆盖并打印出最后一行。

  • 问题内容: 即使已经存在一个类似的主题,我也注意到它可以追溯到两年前,因此我认为打开一个新主题更为合适。 我试图弄清楚如何从Linux内核(3.3.4)发送UDP数据包,以便监视随机数生成器(/drivers/char/random.c)的行为。到目前为止,由于sock_create和sock_sendmsg函数,我已经设法监视了一些事情。您可以在此消息的末尾找到我使用的典型代码。(您可能还希望在

  • 在“数据管理”页面,上方的“追加数据”按钮进入该功能 。 1.该功能会将“源表”里的数据全部复制到“目标表”中 2.两张表的数据类型必须一致。 3.两张表对应列名次序必须完全相同。

  • 问题内容: Linux内核内部用户内存和内核内存的区别是什么 (就给内核空间提供安全性而言)? 我可以从用户空间在内核地址空间中写入什么不同的方式? 我知道的一种方法是通过系统调用 。我们可以使用多个系统调用,但最后它们都是系统调用。即使在系统调用中,我们也将数据发送到内核空间,在此它(驱动程序或相应的模块)调用诸如copy_from_user()之类的函数将数据从用户空间复制到内核空间。在这里,

  • 问题内容: 如何在JavaScript中将对象(例如字符串或数字)附加到数组? 问题答案: 使用该方法将值附加到数组: 您可以使用该函数在单个调用中将多个值附加到数组中: 更新资料 如果要将一个数组的项目添加到另一个数组,则可以使用: 更新资料 如果您想将任何值附加到数组的开头(这意味着第一个索引),则可以添加此答案,您可以为此目的使用它。 它也支持一次附加多个值。

  • PS Vita可游玩从PlayStation®Store下载的PSP™Game。 在此可确认或删除PSP™Game的追加数据。 已插入PS Vita专用存储卡的状态下,轻触[应用程序数据管理]>[追加数据(PSP™)]。