如何使用NetFilter Hooks回显中的核空间中的数据包?[英] How to echo a packet in kernel space using netfilter hooks?

本文是小编为大家收集整理的关于如何使用NetFilter Hooks回显中的核空间中的数据包?的处理方法,想解了如何使用NetFilter Hooks回显中的核空间中的数据包?的问题怎么解决?如何使用NetFilter Hooks回显中的核空间中的数据包?问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我想在内核空间中回显包码.我在此计算机上运行一个带端口6000的echo服务器. 现在,客户端在另一台计算机上运行向回声服务器发送数据.现在,我想做的就是回应从内核空间回来的数据包.我不想用数据包打扰服务器,它将默默地从内核空间静音.我在下面提出我的代码:

#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 <net/checksum.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_echo_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_echo_ops __read_mostly = {
    .pf = NFPROTO_IPV4,
    .priority = 1,
    .hooknum = NF_INET_PRE_ROUTING,
    .hook = pkt_echo_begin,
};

static int __init pkt_echo_init(void)
{
    printk(KERN_ALERT "\npkt_echo module started ...");
    return nf_register_hook(&pkt_echo_ops);
}

static void __exit pkt_echo_exit(void)
{
    nf_unregister_hook(&pkt_echo_ops);
    printk(KERN_ALERT "pkt_echo module stopped ...");
}

static unsigned int pkt_echo_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 *temp;

    __u16 dst_port, src_port;
    int data_len;



    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, TOT_HDR_LEN, 0, NULL);
                data_len = skb->len - TOT_HDR_LEN;

                struct sk_buff *newskb;
                struct iphdr *newiph;
                struct udphdr *newudph;
                unsigned char *newdata;
                unsigned int newdata_len;

                newskb = skb_copy(skb, GFP_ATOMIC);
                newiph = (struct iphdr *) skb_header_pointer (newskb, 0, 0, NULL);
                newudph = (struct udphdr *) skb_header_pointer (newskb, IP_HDR_LEN, 0, NULL);
                newdata = (unsigned char *) skb_header_pointer (newskb, TOT_HDR_LEN, 0, NULL);

                newiph->saddr = iph->daddr;
                newiph->daddr = iph->saddr;

                newudph->source = udph->dest;
                newudph->dest = udph->source;

                struct sk_buff *tempskb;

                tempskb = skb_copy(skb, GFP_ATOMIC);

                *tempskb = *skb;
                *skb = *newskb;
                *newskb = *tempskb;

                kfree_skb(newskb);

            }
        }
    }
    return NF_ACCEPT;
}


module_init(pkt_echo_init);
module_exit(pkt_echo_exit);

MODULE_AUTHOR("Rifat Rahman Ovi: <rifatrahmanovi@gmail.com>");
MODULE_DESCRIPTION("Echoing a packet from kernel space.");
MODULE_LICENSE("GPL");

现在我不明白需要什么.我在pre_routing hook中捕获了数据包. 然后我创建了一个新的skb,从旧的skb填充它,然后改变了 源地址(SADDR),目标地址(DADDR),源端口(源)和目标 端口(DEST),以便可以从PRE_ROUTING HOOK转发数据包.作为路由 在数据包从挂钩传递后进行决策,我查找要转发到其始发源的数据包.但由于某种原因,它没有这样做.收到数据包,并更改了一切,但数据包似乎没有向后移动.我不明白缺少什么,也是需要做什么的东西.更具体地说,从Pre_Routing Hook向网络发送数据包?

推荐答案

很多丢失.

首先,您使用的NetFilter挂钩是预路由,捕获传入数据包,因此,除非您使用一些内核函数来传输您构建的数据包,返回NF_Accept将仅让您更改的数据包(或未删除t)继续(这是本地系统,而不是它).
读取关于函数(如dev_queue_xmit(struct sk_buff *)),但请注意,在使用此函数之前,您的skb必须具有链接层标题,因为此功能实际上将数据包队列队列以立即向NIC发送到NIC,并且它是您的作业来设置链路层地址.

第二,请记住,更改IP-Header地址后,您必须重新计算数据包的校验和,或者您的数据包将在另一端丢弃.

第三,请注意,在内核空间中做你想要做的事情主要被认为是一个非常糟糕的做法. 内核模块存在有原因,这不是其中之一,NetFilter是一个很好的工具,但它并不是真正应该用于发送正常流量.

编辑:

阅读您的最新评论;我建议你仔细阅读Libpcap库,它应该很好地为您服务,仍然在其正确的位置,用户空间保持工作.

其他推荐答案

除上一个答案外,可以使用从NetFilter回调中回应UDP数据包的另一种技术是:

将数据包发送回,作为新的UDP数据包,使用:

int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)

在net/socket.c

或者还使用netpoll库,如答案 .

原始数据包也可以使用nf_drop删除.

在NetFilter回调中,可以在"中断上下文"中运行可以发送数据包,但无法接收它们(因为每次尝试等待导致内核恐慌). 出于这个原因,我提出的解决方案与UDP一起使用,但不能使用TCP(TCP握手需要必须接收ACK消息).

无论如何,如今已经说,在内核空间中做这种事情很糟糕,应该仅用于学习目的.

本文地址:https://www.itbaoku.cn/post/359377.html