【问题标题】:How to read data from sk_buff using netfilter kernel module?如何使用 netfilter 内核模块从 sk_buff 读取数据?
【发布时间】:2015-01-13 17:34:40
【问题描述】:

我们正在编写一个内核模块来为数据包添加一些额外的数据。我们在 skbuff 的数据部分的源中添加 120 字节的数据,并尝试从目标的 skbuff 中提取该数据。

以下是我们在两台机器上运行的内核模块代码。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/slab.h>
#include <linux/inet.h>
#include <linux/time.h>
#include <linux/ktime.h>

static struct nf_hook_ops nf_out;
static struct nf_hook_ops nf_in;

struct my_struct {
// 24 byte struct
};

unsigned int outgoing_hook_func(unsigned int hooknum, struct sk_buff *skb, const struct              net_device *in, const struct net_device *out, int(*okfn)(struct sk_buff *))
{
int i = 0;
struct my_struct *ptr;
unsigned char *new_data;
int size = 5 * sizeof(struct my_struct);
ptr = kmalloc(size, GFP_ATOMIC);
for(i = 0; i < 5; i++) {
    //Assign some values to the array of mystruct
    }
}       
printk("output_Before: %d\n",skb->len);

new_data = skb_tail_pointer(skb);
SKB_LINEAR_ASSERT(skb);
// Add this additional data only if there is enough room in the data section of the skbuff
if (skb->tail + size < skb->end) {
    skb->tail += size;
        skb->len  += size;
        memcpy(new_data, ptr, size);
}

kfree(ptr);
printk("output_After: %d\n",skb->len);
return NF_ACCEPT;
}

unsigned int incoming_hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int(*okfn)(struct sk_buff *))
{
int i = 0;
struct loc_time_tag *ptr;
int size = 5 * sizeof(struct my_struct);
printk("input_Before: %d\n",skb->len);

// Collect data only from packets that have my_struct appended to them

if (skb->tail + size < skb->end) {
    unsigned int tail_ptr = skb_tail_pointer(skb);
    ptr = (struct my_struct *)(tail_ptr - 5 * sizeof(struct my_struct));
    printk("tail = %d; end =  %d; ptr = %d", skb->tail,skb->end, ptr);

    for(i = 0; i < 5; i++) {
    // Print out the values of ptr
    }

}

printk("input_after: %d\n",skb->len);
return NF_ACCEPT;
}

//Called when module loaded using 'insmod'
int init_module()
{
  nf_out.hook = outgoing_hook_func;               
  nf_out.hooknum = NF_INET_LOCAL_OUT;         
  nf_out.pf = PF_INET;
  nf_out.priority = NF_IP_PRI_FIRST;
  nf_register_hook(&nf_out);

  nf_in.hook = incoming_hook_func;
  nf_in.hooknum = NF_INET_LOCAL_IN;
  nf_in.pf = PF_INET;
  nf_in.priority = NF_IP_PRI_FIRST;
  nf_register_hook(&nf_in);
  return 0;             
}

//Called when module unloaded using 'rmmod'
void cleanup_module()
{
  nf_unregister_hook(&nf_out);                     //cleanup – unregister hook
  nf_unregister_hook(&nf_in);
}

但是当我们在源和目标之间执行简单的操作(如 SSH)并检查两台机器上的 wireshark 跟踪时,以下是我们的观察结果。

  1. 如果incoming_hook_func 和outgoing_hook_func 都在源机器和目标机器上注册并运行,wireshark 会为从源机器传出的数据包显示“ETHERNET FRAME CHECKSUM SEQUENCE INCORRECT”错误。在目标机器上没有看到任何数据包。我不确定数据包是否没有离开源机器,或者目的地是否无法读取数据包。 一段时间后,源和目标都崩溃了。 (我们假设这是由于 incoming_hook_func() 代码中的一些错误)

  2. 1234563不回复该数据包。 在这种情况下没有出现系统崩溃。

如果有人能用给定的信息回答以下问题,我们将不胜感激。

  1. 以太网帧校验序列在哪里计算?它是在内核中完成的还是由wireshark完成的?我们应该怎么做才能克服wireshark中显示的错误。添加数据后是否需要重新计算校验和?

  2. 我们的输出挂钩函数不会使系统崩溃,因此我们假设我们在该例程中的指针操作是正常的。但是incoming_hook_func 会导致系统崩溃。有人可以告诉我们哪里出错了吗?

  3. 在上述情况 2 中,为什么目的地没有响应?是因为帧检查顺序不好还是我们对事物的理解有任何其他缺陷。

  4. 此外,在上述两种情况下,ping 测试似乎都运行良好。我们无法理解为什么会这样。

提前致谢

【问题讨论】:

    标签: c networking linux-kernel kernel-module netfilter


    【解决方案1】:
    unsigned int tail_ptr = skb_tail_pointer(skb);
    ptr = (struct my_struct *)(tail_ptr - 5 * sizeof(struct my_struct));
    

    将上面的代码替换为以下代码。

    unsigned char* tail_ptr = skb_tail_pointer(skb);
    ptr = (struct my_struct *)(tail_ptr - 5 * sizeof(struct my_struct));
    

    这将是从尾指针向后移动 5 * 24 字节的正确方法。这或许可以解释您崩溃的原因。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-17
      • 2021-04-30
      • 2022-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多