我正在为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);
答案 0 :(得分:6)
我浏览了内核网络代码(自从我在那里做了一年之后的一年),我认为你应该能够做到这一点而不会漏掉任何东西:
kfree_skb(skb);
return NET_RX_DROP;
修改强>
这在其他协议处理程序中完成,例如ip_rcv
和arp_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仍将继续使用其他处理程序。
答案 1 :(得分:6)
您正在使您的模块处理所有以太网数据包。 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;
}