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

查看:18
本文介绍了如何使用 netfilter 钩子在内核空间中回显数据包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在内核空间回显一个数据包.我在这台机器上用端口 6000 运行一个回显服务器.现在客户端运行在另一台机器上,向回显服务器发送数据.现在,我想要做的是从内核空间回显数据包.我不想用数据包打扰服务器,它会从内核空间静默回响.我在下面展示我的代码:

I want to echo a packet in kernel space. I run an echo server on this machine with port 6000. Now a client runs on another machine sending data to the echo server. Now, what I want to do is to echo the packet back from the kernel space. I do not want to bother the server with the packet, and it will be echoed silently from the kernel space. I am presenting my codes below:

#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 "
pkt_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 "
UDP 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 钩子中捕获了数据包.然后我创建了一个新的 skb,从旧的接收到的 skb 填充它,然后改变了源地址(saddr)、目的地址(daddr)、源端口(source)、目的端口(dest),以便可以从 PRE_ROUTING 钩子转发数据包.作为路由在数据包从钩子通过后做出决定,我寻找要转发到其原始源的数据包.但出于某种原因,它并没有这样做.收到数据包,一切都改变了,但数据包似乎没有向后移动.我不明白缺少什么,也不明白需要什么才能使它工作.更具体地说,从 PRE_ROUTING 钩子向网络发送数据包需要什么?

Now I do not understand what is needed. I captured the packet in the PRE_ROUTING hook. Then I created a new skb, populated it from the old received skb, and then altered the source address (saddr), destination address (daddr), source port (source), and destination port (dest), so that the packet can be forwarded from the PRE_ROUTING hook. As routing decisions are made after the packet passes from the hook, I look for the packet to be forwarded to its originating source. But for some reason it is not doing like that. The packet is received, and everything is altered, but the packet does not seem to move backwards. I do not understand what is missing, and also what is needed to make it work. More specifically, what is needed to send a packet to the network from a PRE_ROUTING hook?

推荐答案

缺少很多东西.

A lot is missing.

首先,您使用的 netfilter 钩子是 PRE-ROUTING,它捕获传入的数据包,因此除非您使用某些内核函数来传输您构建的数据包,否则返回 NF_ACCEPT 只会让您更改(或未更改)的数据包t) 继续前进(这是到本地系统,而不是从本地系统).
阅读诸如 dev_queue_xmit(struct sk_buff *) 之类的函数,但请注意,在使用此函数之前,您的 SKB 必须具有链路层标头,因为此函数实际上将您的数据包排入队列以立即发送到 NIC,您的工作就是设置链路层地址.

First of all, the netfilter hook you used is PRE-ROUTING which captures INCOMING packets and so unless you use some kernel function to transmit the packet you've built, return NF_ACCEPT will only let the packet you altered(or didn't) continue on its way (which is TO the local system, not from it).
Read about functions like dev_queue_xmit(struct sk_buff *) but notice that before using this function, your SKB has to have the Link-layer header because this function actually queues your packet in a queue to be sent right away to the NIC and it's your job to set the Link layer addresses.

其次,请记住,在更改 IP 头地址后,您必须重新计算数据包的校验和,否则您的数据包将在另一端被丢弃.

Second, remember that after you alter the IP-header addresses you have to re-calculate the checksum of the packet or else your packet will be discarded at the other end.

第三,请注意,在内核空间中执行您尝试执行的操作在很大程度上被认为是一种非常糟糕的做法.内核模块的存在是有原因的,这不是其中之一,netfilter 是一个很棒的工具,但它并不真正应该用于发送正常流量.

Third, notice that doing what you're trying to do in kernel space is largely considered a VERY bad practice. Kernel modules exist for a reason and this is not one of them, netfilter is a great tool, but it's not really supposed to be used for sending normal traffic.

阅读您的最新评论;我建议您阅读有关 libPCap 库的信息,它应该会很好地为您服务,并且仍然可以将您的工作保存在正确的位置,即用户空间.

Reading your latest comment; I'd suggest you read about libPCap library, it should serve you very well and still keep your work in its right place, the user-space.

这篇关于如何使用 netfilter 钩子在内核空间中回显数据包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆