我们正在编写内核模块以向数据包添加一些额外的数据。我们在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跟踪时,我们的观察结果如下。
如果incoming_hook_func和outgoing_hook_func都在源计算机和目标计算机上都已注册并运行,则wireshark会对从源计算机发出的数据包显示“ETHERNET FRAME CHECKSUM SEQUENCE INCORRECT”错误。目标计算机上未显示任何数据包。我不确定数据包是否未离开源计算机或目标无法读取数据包。 一段时间后,源和目标都崩溃了。 (我们假设这是由于incoming_hook_func()代码中的一些错误)
如果仅在源计算机上注册了outgoing_hook_func而目标上没有任何内容,则在源跟踪上看到相同的“ETHERNET FRAME CHECKSUM SEQUENCE INCORRECT”,此数据包在目的地上被视为已接收,但目的地不回复该数据包。 在这种情况下,没有看到系统崩溃。
如果有人能够用给定的信息回答以下问题,我们将非常感激。
以太网帧校验序列究竟在哪里计算?它是在内核中完成还是由wireshark完成的?我们该怎么做才能克服wireshark中显示的错误。我们应该在添加数据后重新计算任何校验和吗?
我们的outgoing_hook_func不会使系统崩溃,所以我们假设我们在该例程中的指针操作很好。但incoming_hook_func导致系统崩溃。有人可以告诉我们哪里出错了吗?
在上面的案例2中,为什么目的地没有响应?是由于糟糕的帧检查顺序还是我们对事物的理解还存在其他缺陷。
此外,在上述两种情况下,ping测试似乎都运行良好。我们无法理解为什么会出现这种情况。
提前致谢
答案 0 :(得分:2)
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字节的正确方法。这可能解释了您崩溃的原因。