C语言 如何使用 net_dev_add() API 过滤和拦截 Linux 数据包



我正在为 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, worldn");
}
module_init(hello_init);
module_exit(hello_exit);

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

如果不更改内核代码,则无法更改此行为。一种可能性是创建一个网络过滤器模块。这样,您可以在ip_rcv函数之后拦截数据包,并根据需要丢弃它(在网络过滤器中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 hookn");
    }
    return err;
}

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

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,然后 Netfilter 调用 ip_rcv_finish(如果它没有删除它(。 如果出现问题,它会释放 skb 并返回。

编辑

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

最新更新