如何在内核空间中使用 netfilter 钩子路由分割的数据包

2023-12-02

我必须在 PRE_ROUTING 挂钩中将大数据包拆分为较小的数据包。我已经完成了将数据包分割成更小的数据包、创建 skb、设置 ip 和 udp 标头等的必要步骤。但我不明白的是如何路由数据包?我现在可以在数据包中附加数据(可以在我之前的问题中看到:如何从内核空间向数据包追加数据?)。但现在我陷入了路由分割数据包的困境。提前致谢。

我在下面给出了我的代码(到目前为止我可以写)。 让我们想象该模块在服务器计算机上运行。服务器在端口 6000 上运行。然后客户端发送一条消息“ThisIsUsedForTesting”。根据代码,服务器应该得到“ThisI”:一个较小的数据包。我现在不关心第二包。我可以轻松地改变数据包大小。但现在可以有两个或更多数据包。

运行该模块后,服务器收到消息:“ThisI”。但当回响时, 包装盒未开箱。我为 PRE_ROUTING 编写了模块,然后机器应该立即 oops,但是服务器进程收到消息,然后机器就 oops。 我不明白这些场景。欢迎任何帮助/建议。如果我可以管理第一个分割的数据包,我想,其余的数据包可以自动处理,所以这里没有给出它们的代码:

    #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>
    #include <linux/netfilter_ipv4.h>

    #define IP_HDR_LEN 20
    #define UDP_HDR_LEN 8
    #define TOT_HDR_LEN 28

    static unsigned int pkt_split_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 skb_print_info(const struct sk_buff *skb);
    static void ip_print_info(struct iphdr *iph);
    static void udp_print_info(struct udphdr *udph);
    static void data_print_info(unsigned char *data, int len);

    static struct nf_hook_ops pkt_split_ops __read_mostly = {
        .pf = NFPROTO_IPV4,
        .priority = 1,
        .hooknum = NF_INET_PRE_ROUTING,
        .hook = pkt_split_begin,
    }; 

static int __init pkt_split_init(void)
{
    printk(KERN_ALERT "\npkt_split module started ...");
    return nf_register_hook(&pkt_split_ops);
}

static void __exit pkt_split_exit(void)
{
    nf_unregister_hook(&pkt_split_ops);
    printk(KERN_ALERT "pkt_split module stopped ...");
}

static unsigned int pkt_split_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 int i;

    unsigned char *temp;
    unsigned char *temp1, *temp2;
    unsigned char *ptr;

    __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 (dst_port == 6000) {
                printk(KERN_ALERT "\nUDP packet goes in");
                data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL);
                data_len = skb->len - TOT_HDR_LEN;

                temp = kmalloc(50 * sizeof(char), GFP_ATOMIC);
                memcpy(temp, data, data_len);

                temp1 = kmalloc(50 * sizeof(char), GFP_ATOMIC);
                temp2 = kmalloc(50 * sizeof(char), GFP_ATOMIC);

                unsigned int len1, len2;

                len1 = 5;
                len2 = data_len - len1;

                memcpy(temp1, temp, len1);
                temp1[len1] = '\0';
                printk(KERN_ALERT "temp1: %s", temp1);

                ptr = temp + len1;
                memcpy(temp2, ptr, len2);
                printk(KERN_ALERT "temp2: %s", temp2);

                struct sk_buff *skb1, *skb2;
                struct iphdr *iph1, *iph2;
                struct udphdr *udph1, *udph2;
                unsigned char *data1, *data2;
                int data_len1, data_len2;

                skb1 = skb_copy(skb, GFP_ATOMIC);
                skb2 = skb_copy(skb, GFP_ATOMIC);

                iph1 = (struct iphdr *) skb_header_pointer(skb1, 0, 0, NULL);
                udph1 = (struct udphdr *) skb_header_pointer(skb1, IP_HDR_LEN, 0, NULL);
                data1 = (unsigned char *) skb_header_pointer(skb1, TOT_HDR_LEN, 0, NULL);
                data_len1 = skb1->len - len2 - TOT_HDR_LEN + 1;

                memset(data1, 0, data_len);
                memcpy(data1, temp1, data_len1);
                skb1->len = data_len1 + TOT_HDR_LEN;
                iph1->tot_len = htons(data_len1 + TOT_HDR_LEN);
                udph1->len = htons(data_len1 + UDP_HDR_LEN);
                skb1->tail = skb1->tail - data_len2 + 1;


                /* Calculation of IP header checksum */
                iph1->check = 0;
                ip_send_check (iph1);

                /* Calculation of UDP checksum */
                udph1->check = 0;
                int offset = skb_transport_offset(skb1);
                int len = skb1->len - offset;
                udph1->check = ~csum_tcpudp_magic((iph1->saddr), (iph1->daddr), len, IPPROTO_UDP, 0);

                struct sk_buff *tempskb;

                tempskb = skb_copy(skb, GFP_ATOMIC);

                *tempskb = *skb;
                *skb = *skb1;
                *skb1 = *tempskb;

                (*okfn)(skb);

                skb_print_info(skb1);
                ip_print_info(iph1);
                udp_print_info(udph1);
                data_print_info(data1, data_len1);

                kfree_skb(skb1);

            }
        }
    }
    return NF_DROP;
}

static void skb_print_info (const struct sk_buff *skb)
{
    printk(KERN_ALERT "\nPrinting SKB info: ");

    printk(KERN_ALERT "len: %d", skb->len);
    printk(KERN_ALERT "tail: %d", skb->tail);
    printk(KERN_ALERT "end: %d", skb->end);
    printk(KERN_ALERT "head: %x", skb->head);
    printk(KERN_ALERT "data: %x", skb->data);

    printk(KERN_ALERT "\ntail pointer = %x", skb_tail_pointer(skb));
    printk(KERN_ALERT "end pointer = %x", skb_end_pointer(skb));
    printk(KERN_ALERT "\nheadroom = %d", skb_headroom(skb));
    printk(KERN_ALERT "\ntailroom = %d", skb_tailroom(skb));

}

void ip_print_info (struct iphdr *iph)
{
    printk(KERN_ALERT "\nPrinting IP header info:");

    printk(KERN_ALERT "ihl = %d", iph->ihl);
    printk(KERN_ALERT "version = %d", iph->version);
    printk(KERN_ALERT "tos = %d", iph->tos);
    printk(KERN_ALERT "tot_len = %d", ntohs(iph->tot_len));
    printk(KERN_ALERT "id = %d", ntohs(iph->id));
    printk(KERN_ALERT "frag_off = %d", ntohs(iph->frag_off));
    printk(KERN_ALERT "ttl = %d", iph->ttl);
    printk(KERN_ALERT "protocol = %d", iph->protocol);
    printk(KERN_ALERT "check = %x", ntohs(iph->check));
    printk(KERN_ALERT "saddr = %x", ntohl(iph->saddr));
    printk(KERN_ALERT "daddr = %x", ntohl(iph->daddr));
}

void udp_print_info (struct udphdr *udph)
{
    printk(KERN_ALERT "\nPrinting UDP header info: ");

    printk(KERN_ALERT "source = %d", ntohs(udph->source));
    printk(KERN_ALERT "dest = %d", ntohs(udph->dest));
    printk(KERN_ALERT "len = %d", ntohs(udph->len));
    printk(KERN_ALERT "check = %x", ntohs(udph->check));
}


void data_print_info (unsigned char *data, int len)
{
    printk(KERN_ALERT "\nPrinting data info: ");

    printk(KERN_ALERT "Data: %s", data);
    printk(KERN_ALERT "data_len: %d", len);
}

module_init(pkt_split_init);
module_exit(pkt_split_exit);

MODULE_AUTHOR("Rifat Rahman Ovi: <[email protected]>");
MODULE_DESCRIPTION("Outward Packet Mangling and Decryption in Kernel Space");
MODULE_LICENSE("GPL");

这次我找到了解决办法。这也是一个与前一个类似的简单情况(http://stackoverflow.com/questions/12529497/how-to-append-data-on-a-packet-from-kernel-space)。我正在展示代码。但有件事我需要解释一下。

okfn

必须这样称呼

okfn(skb);

并且它会释放 skb 本身。我的问题是关于双重释放 skb。查看下面的代码,您就会明白完成它需要什么。 该代码仅用于测试目的。将使用前 5 个字节(加上 '\0') 构建一个新数据包,其余数据用于创建第二个数据包。那么,我们开始吧。为了方便起见,提供了打印 skb 信息、ip 标头信息等所需的辅助函数(我用它来了解发生了什么)。

#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>
#include <linux/netfilter_ipv4.h>

#define IP_HDR_LEN 20
#define UDP_HDR_LEN 8
#define TOT_HDR_LEN 28

static unsigned int pkt_split_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 skb_print_info(const struct sk_buff *skb);
static void ip_print_info(struct iphdr *iph);
static void udp_print_info(struct udphdr *udph);
static void data_print_info(unsigned char *data, int len);

static struct nf_hook_ops pkt_split_ops __read_mostly = {
    .pf = NFPROTO_IPV4,
    .priority = 1,
    .hooknum = NF_INET_PRE_ROUTING,
    .hook = pkt_split_begin,
};

static int __init pkt_split_init(void)
{
    printk(KERN_ALERT "\npkt_split module started ...");
    return nf_register_hook(&pkt_split_ops);
}

static void __exit pkt_split_exit(void)
{
    nf_unregister_hook(&pkt_split_ops);
    printk(KERN_ALERT "pkt_split module stopped ...");
}

static unsigned int pkt_split_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 int i;

    unsigned char *temp;
    unsigned char *temp1, *temp2;
    unsigned char *ptr;

    __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 (dst_port == 6000) {
                printk(KERN_ALERT "\nUDP packet goes in");
                data = (unsigned char *) skb_header_pointer (skb, IP_HDR_LEN+UDP_HDR_LEN, 0, NULL);
                data_len = skb->len - TOT_HDR_LEN;

                temp = kmalloc(50 * sizeof(char), GFP_ATOMIC);
                memcpy(temp, data, data_len);

                temp1 = kmalloc(50 * sizeof(char), GFP_ATOMIC);
                temp2 = kmalloc(50 * sizeof(char), GFP_ATOMIC);

                unsigned int len1, len2;

                len1 = 5;
                len2 = data_len - len1;

                memcpy(temp1, temp, len1);
                temp1[len1] = '\0';
                printk(KERN_ALERT "temp1: %s", temp1);

                ptr = temp + len1;
                memcpy(temp2, ptr, len2);
                printk(KERN_ALERT "temp2: %s", temp2);

                struct sk_buff *skb1, *skb2;
                struct iphdr *iph1, *iph2;
                struct udphdr *udph1, *udph2;
                unsigned char *data1, *data2;
                int data_len1, data_len2;

                skb1 = skb_copy(skb, GFP_ATOMIC);
                skb2 = skb_copy(skb, GFP_ATOMIC);

                iph1 = (struct iphdr *) skb_header_pointer(skb1, 0, 0, NULL);
                udph1 = (struct udphdr *) skb_header_pointer(skb1, IP_HDR_LEN, 0, NULL);
                data1 = (unsigned char *) skb_header_pointer(skb1, TOT_HDR_LEN, 0, NULL);
                data_len1 = skb1->len - len2 -TOT_HDR_LEN + 1;

                memset(data1, 0, data_len);
                memcpy(data1, temp1, data_len1);
                skb1->len = data_len1 + TOT_HDR_LEN;
                iph1->tot_len = htons(data_len1 + TOT_HDR_LEN);
                udph1->len = htons(data_len1 + UDP_HDR_LEN);
                skb1->tail = skb1->tail - data_len2 + 1;

                /* Calculation of IP header checksum */
                iph1->check = 0;
                ip_send_check (iph1);

                /* Calculation of UDP checksum */
                udph1->check = 0;
                int offset = skb_transport_offset(skb1);
                int len = skb1->len - offset;
                udph1->check = ~csum_tcpudp_magic((iph1->saddr), (iph1->daddr), len, IPPROTO_UDP, 0);

                /* Dealing with the second packet */
                iph2 = (struct iphdr *) skb_header_pointer(skb2, 0, 0, NULL);
                udph2 = (struct udphdr *) skb_header_pointer(skb2, IP_HDR_LEN, 0, NULL);
                data2 = (unsigned char *) skb_header_pointer(skb2, TOT_HDR_LEN, 0, NULL);
                data_len2 = skb2->len - len1 - TOT_HDR_LEN;

                memset(data2, 0, data_len);
                memcpy(data2, temp2, data_len2);
                skb2->len = data_len2 + TOT_HDR_LEN;
                iph2->tot_len = htons(data_len2 + TOT_HDR_LEN);
                udph2->len = htons(data_len2 + UDP_HDR_LEN);
                skb2->tail = skb2->tail - data_len1;

                /* Calculation of IP header checksum */
                iph2->check = 0;
                ip_send_check (iph2);

                /* Calculation of UDP checksum */
                udph2->check = 0;
                offset = skb_transport_offset(skb1);
                len = skb2->len - offset;
                udph2->check = ~csum_tcpudp_magic((iph2->saddr), (iph2->daddr), len, IPPROTO_UDP, 0);

                okfn(skb1);
                okfn(skb2);
            }
        }
    }
    return NF_DROP;
}

static void skb_print_info (const struct sk_buff *skb)
{
    printk(KERN_ALERT "\nPrinting SKB info: ");

    printk(KERN_ALERT "len: %d", skb->len);
    printk(KERN_ALERT "tail: %d", skb->tail);
    printk(KERN_ALERT "end: %d", skb->end);
    printk(KERN_ALERT "head: %x", skb->head);
    printk(KERN_ALERT "data: %x", skb->data);

    printk(KERN_ALERT "\ntail pointer = %x", skb_tail_pointer(skb));
    printk(KERN_ALERT "end pointer = %x", skb_end_pointer(skb));
    printk(KERN_ALERT "\nheadroom = %d", skb_headroom(skb));
    printk(KERN_ALERT "\ntailroom = %d", skb_tailroom(skb));

}

void ip_print_info (struct iphdr *iph)
{
    printk(KERN_ALERT "\nPrinting IP header info:");

    printk(KERN_ALERT "ihl = %d", iph->ihl);
    printk(KERN_ALERT "version = %d", iph->version);
    printk(KERN_ALERT "tos = %d", iph->tos);
    printk(KERN_ALERT "tot_len = %d", ntohs(iph->tot_len));
    printk(KERN_ALERT "id = %d", ntohs(iph->id));
    printk(KERN_ALERT "frag_off = %d", ntohs(iph->frag_off));
    printk(KERN_ALERT "ttl = %d", iph->ttl);
    printk(KERN_ALERT "protocol = %d", iph->protocol);
    printk(KERN_ALERT "check = %x", ntohs(iph->check));
    printk(KERN_ALERT "saddr = %x", ntohl(iph->saddr));
    printk(KERN_ALERT "daddr = %x", ntohl(iph->daddr));
}

void udp_print_info (struct udphdr *udph)
{
    printk(KERN_ALERT "\nPrinting UDP header info: ");

    printk(KERN_ALERT "source = %d", ntohs(udph->source));
    printk(KERN_ALERT "dest = %d", ntohs(udph->dest));
    printk(KERN_ALERT "len = %d", ntohs(udph->len));
    printk(KERN_ALERT "check = %x", ntohs(udph->check));
}


void data_print_info (unsigned char *data, int len)
{
    printk(KERN_ALERT "\nPrinting data info: ");

    printk(KERN_ALERT "Data: %s", data);
    printk(KERN_ALERT "data_len: %d", len);
}

module_init(pkt_split_init);
module_exit(pkt_split_exit);

MODULE_AUTHOR("Rifat Rahman Ovi: <[email protected]>");
MODULE_DESCRIPTION("Inward Packet Splitting in kernel space");
MODULE_LICENSE("GPL");

所以...由于我是内核空间编程的新手,欢迎提出任何改进建议。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在内核空间中使用 netfilter 钩子路由分割的数据包 的相关文章

随机推荐

  • 确定 Active Directory 搜索结果中用户的域[重复]

    这个问题在这里已经有答案了 可能的重复 如何从 AD DirectoryEntry 获取 DOMAIN USER 这是我现在所拥有的 DirectoryEntry de new DirectoryEntry LDAP domain Sear
  • 我们应该在链接的绝对路径中使用正斜杠 / 或反斜杠 \ 吗?

    所有这些链接的绝对路径都运行良好 img src alt img src alt img src alt 但我应该使用哪一个呢 推荐的是哪一款呢 它们之间有什么区别 URL 使用正斜杠 在所有平台上 反斜杠 用于 Windows 上的本地文
  • 如何确保一个事件只订阅一次

    我想确保我只在特定类中订阅实例上的事件一次 例如 我希望能够执行以下操作 if not already subscribed member Event new MemeberClass Delegate handler 我将如何实施这样的警
  • angularjs - 测试控制器

    我刚刚开始使用 Angular 我想为我的控制器编写一些简单的单元测试 这就是我得到的 app js use strict Declare app level module which depends on filters and serv
  • 一步步在 macOS 上编写 hello world

    我在 mac os x86 64 架构 的汇编方面遇到了很大的困难 我想向您介绍 hello world 程序的解释 如果您能向我提供反馈意见以及建议和解释 我将不胜感激 话虽如此 让我们进入代码 你好世界程序 Never felt the
  • 使用条件格式按类别交替设置数据格式

    我有一个电子表格 其中有很多行 如下所示 Name ID Category Attributes name0 753 cat1 name1 724 cat1 name2 149 cat1 name3 265 cat1 name4 032 c
  • 在 C 风格方法中访问实例变量

    有人可以确认您无法从同一类的 C 风格函数中访问 Objective C implementation 块中定义的实例变量吗 编译器抛出错误 提示 XXX 未声明 其中 XXX 是实例变量名称 这是我要解释的示例 interface Fon
  • 通过 Actionscript 3.0 使用 HTTP POST 上传 zip 文件

    我有一个 zip 文件 该文件是通过在桌面 Flex 4 6 应用程序中的视图上拖放而创建的 这会触发自动上传 zip 文件的服务 我可以使用以下代码将有关 zip 文件的元数据发送到服务器 var urlRequest URLReques
  • 在 Symfony 2.8、3.0 及更高版本中将数据传递给 buildForm()

    我的应用程序当前使用构造函数将数据传递到我的表单类型 如中所建议的这个答案 但是 那Symfony 2 8 升级指南建议将类型实例传递给createForm函数已弃用 将类型实例传递给 Form add FormBuilder add 和
  • Google Maps API v3 - infoWindows 均具有相同的内容

    我在使用 infoWindows 和 Google Maps API v3 时遇到了问题 最初 我遇到了其他人在打开新窗口时关闭 infoWindows 的问题 我想通过预先定义 infowindow 来解决这个问题 现在 当我单击新标记时
  • file_get_contents 脚本适用于某些网站,但不适用于其他网站

    我正在寻找构建一个 PHP 脚本来解析 HTML 中的特定标签 我一直在使用这个代码块 改编自这个tutorial 该脚本适用于某些网站 例如上面的 google 但是当我尝试使用其他网站 例如 freshdirect 时 我收到此错误 警
  • pyplot散点图标记大小

    在散点图的 pyplot 文档中 matplotlib pyplot scatter x y s 20 c b marker o cmap None norm None vmin None vmax None alpha None line
  • 我想在 React 的画布上录制视频

    我查了很久 觉得有必要在这里问一下 我之前使用的 npm 包什么也没做 有人曾经做过或经历过这样的应用吗 我想做的就是在画布元素上绘图时将其录制为视频 提前致谢 是的 您可以使用媒体流 捕获流 and 媒体记录器为了那个原因 下面是一个示例
  • VBA执行字符串中的代码

    我正在尝试执行字符串内的 vba 代码 而不将代码写入临时文件中 例如 Dim code As String code n 0 e i e 0 For e i e 0 To 100 n 1 Next 我尝试过 Eval Evaluate R
  • 如何更改行尾约定?

    我有一个我认为很简单的任务 我需要创建一个在行尾使用 unix LF 约定的文本文件 然而 当我尝试使用 pandas to csv 来完成此操作时 我最终得到了 CR LF 如果我留在我的机器上并且我使用 python 来处理所有事情 这
  • 动态创建电子表格菜单项

    我正在尝试使用 Google Apps 脚本在 Google 表格中创建动态填充的菜单 我有一张 课程 表 其中列出了我教授的课程 在运行我的脚本时 我让脚本读取这些类并将其加载到数组中 为了仅在原始 类 表中硬编码值 我想为每个类创建一个
  • Google 地图自定义信息框

    我正在尝试按照此示例合并自定义信息框 但我的代码不起作用 有人可以看一下我哪里出错了吗 我已经评论了示例代码的开始 结束位置以及我试图调用它的位置 function initialize var mapOptions zoom 12 cen
  • IntelliJ IDEA 中代码生成的自定义

    我使用 IntelliJ IDEA 12 我可以自定义使用 重构 功能生成的代码吗 例如 我想更改设置生成 封装字段 的模板 public void setField String field this field field to pub
  • 为什么从标准模块(而不是用户窗体)调用 VBA 代码时运行速度更快?

    Alternate Title Why does pressing Esc make my MS Word macro run faster 在等待一些代码运行时 我偶然发现了一些有趣的事情 Code runs slow press Esc
  • 如何在内核空间中使用 netfilter 钩子路由分割的数据包

    我必须在 PRE ROUTING 挂钩中将大数据包拆分为较小的数据包 我已经完成了将数据包分割成更小的数据包 创建 skb 设置 ip 和 udp 标头等的必要步骤 但我不明白的是如何路由数据包 我现在可以在数据包中附加数据 可以在我之前的