【问题标题】:How to filter and intercept Linux packets by using net_dev_add() API?如何使用 net_dev_add() API 过滤和拦截 Linux 数据包?
【发布时间】:2013-10-20 22:58:13
【问题描述】:

我正在为 linux 编写以太网网络驱动程序。我想接收数据包,编辑并重新发送它们。 我知道如何在packet_interceptor 函数中编辑数据包,但是如何在此函数中丢弃传入的数据包??

#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/sock.h>

struct packet_type my_proto;

int packet_interceptor(struct sk_buff *skb,
    struct net_device *dev,
    struct packet_type *pt,
    struct net_device *orig_dev) {

    // I dont want certain packets go to upper in net_devices for further processing.
    // How can I drop sk_buff here?!

  return 0;
}

static int hello_init( void ) {
    printk(KERN_INFO "Hello, world!\n");

    my_proto.type = htons(ETH_P_ALL);
    my_proto.dev = NULL;
    my_proto.func = packet_interceptor;

    dev_add_pack(&my_proto);
    return 0;
}    

static void hello_exit(void) {
  dev_remove_pack(&my_proto);
  printk(KERN_INFO "Bye, world\n");
}

module_init(hello_init);
module_exit(hello_exit);

【问题讨论】:

  • 你用我的解决方案测试了吗?
  • 嗨@Atle,这几天我的电脑出了点问题。感谢您的回复,一旦我可以启动我的电脑,我将对其进行测试:D。但我记得在我问你之前,我测试了这个解决方案,但它没有奏效。我会再托盘它。
  • 除了使用 netfilter 或 rx_handler 之外,是否有任何解决方案?

标签: c network-programming linux-device-driver kernel-module netfilter


【解决方案1】:

您正在让您的模块处理所有以太网数据包。 Linux 会将数据包发送到所有匹配的协议处理程序。由于 IP 已经在您的内核中注册,因此您的模块和 ip_rcv 都将接收所有带有 IP 标头的 SKB。

如果不更改内核代码,您将无法更改此行为。一种可能性是创建一个 netfilter 模块。这样,您可以在 ip_rcv 函数之后拦截数据包,并根据需要丢弃它(在 Netfilters PREROUTING 钩子中)。

这是一个小的 Netfilter 模块,它是我从我已经编写的一些代码中提取的。本模块未完成,但主要内容已到位。

#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>

// Handler function
static unsigned int my_handler (
    unsigned int hook,
    struct sk_buff *skb,
    const struct net_device *in,
    const struct net_device *out,
    int (*okfn)(struct sk_buff *))
{
    return NF_ACCEPT;
// or
    return NF_DROP;
}

// Handler registering struct
static struct nf_hook_ops my_hook __read_mostly = {
    .hook = my_handler,
    .pf = NFPROTO_IPV4,
    .hooknum = (1 << NF_INET_PRE_ROUTING),
    .priority = NF_IP_PRI_FIRST // My hook will be run before any other netfilter hook
};

int my_init() {
    int err = nf_register_hook (&my_hook);
    if (err) {
            printk (KERN_ERR "Could not register hook\n");
    }
    return err;
}

【讨论】:

  • 我已经测试了 netfilter,它工作得很好,但是我需要放弃 dev_add_pack() 钩子。我的问题是,如果系统有两个处理程序(ip_rcv,my_packet_interceptor),当我在我的一个处理程序中更改 skb 时,它们中的哪一个是有效的? (假设我已经更改了my_packet_interceptor中的skb,所以我有两个skb,originalchanged,它们中的哪一个会进一步处理?)
  • 处理程序一个接一个地运行。我猜想首先运行 IP,因为它可能在您的模块之前注册。我认为现阶段不会复制SKB,因此IP可能会在您更改之前完成。
  • 那么,如果处理程序一个接一个地运行,为什么我不能丢弃数据包?
  • 将 SKB 交给所有协议处理程序的函数在这里:lxr.free-electrons.com/source/net/core/dev.c#L3481。如您所见,来自deliver_skb(它又调用actua 处理函数)的返回值被忽略了。循环无论如何都会继续。因此,如果两个协议处理程序获得了 SKB,则不能删除它。
【解决方案2】:

我浏览了内核网络代码(自从我在里面做任何事情以来已经一年了),我认为你应该能够做到这一点而不会泄漏任何东西:

kfree_skb(skb);
return NET_RX_DROP;

编辑

这是在其他协议处理程序中完成的,例如 ip_rcvarp_rcv(最后一个返回 0 而不是 NET_RX_DROP,但我认为返回值并不重要)。如果您删除 skb,请记住不要调用任何其他处理程序。

查看 ip.c 中ip_rcv 的代码(在底部):http://lxr.free-electrons.com/source/net/ipv4/ip_input.c#L375

如果一切顺利,它会将 skb 传递给 Netfilter,然后调用 ip_rcv_finish(如果它没有丢弃它)。如果出现问题,它会释放 skb 并返回。

编辑

如果多个协议处理程序匹配一个 SKB,内核会将其发送给所有这些处理程序。当您在其中一个模块中kfree_skb() 时,SKB 仍将继续存在于其他处理程序中。

【讨论】:

  • 今天我测试了,但是没有用。它有什么问题?
  • “没用”是什么意思?数据包是否被系统接收而不是被丢弃?数据包甚至进入您的模块吗?
  • 我正在接收packet_interceptor 处理程序中的所有数据包,但系统接收到的所有数据包。 paste.ubuntu.com/6324987
  • 我用 netfilter 模块做了一个例子。内核中发生的事情是,由于 IP 的协议处理程序也已注册,内核将 SKB 发送到您的模块和 IP。当您kfree_skb() 时,您将用户计数器减一,但 IP 也在使用它,因此它不会被释放和丢弃。
  • 我认为当您使用 ETH_P_ALL 时,它会使用 ptype_all 并复制所有数据包......我认为 ptype_base 想要使用(另一种类型而不是 ETH_P_ALL)......
猜你喜欢
  • 2013-11-21
  • 2023-03-14
  • 2011-04-24
  • 2013-01-31
  • 2013-10-07
  • 1970-01-01
  • 1970-01-01
  • 2013-07-04
  • 1970-01-01
相关资源
最近更新 更多