Linux内核抓包-抓取到达网卡的所有报文
因项目需要,我要实现从设备的指定网卡处接收所有流经该网卡的报文并进行处理。
最开始使用的是 netfilter 勾子,结果发现该方法只能获取到目的MAC地址为本地网卡的网络层报文(包括广播报文)。发往其它MAC地址的报文以及链路层报文(如LLDP、GOOSE等)无法被获取。
之后又尝试使用 dev_add_pack() 的方式进行自定义回调函数的注册,以达到替代内核处理报文的目的。结果发现效果跟netfilter一样。只好去咨询老前辈,被告知可以试试利用网桥来实现,折腾了半天发现居然有效。但查看内核源码发现,内核对网桥的处理在我们自定义的回调函数之后,从原理上讲不通。
最后无意间发现原来真正起作用的不是网桥,而是设置网桥后被自动开启的混杂模式。
// 说明:本模块要想像wireshark那样获取所有到达网卡的报文,需满足两个条件:网卡启动;开启混杂模式。
// ifconfig eth0 up promisc
// 内核版本:4.19.26
#include <linux/module.h>
#include <linux/netdevice.h>
//#include <linux/string.h> // 字符串处理
#define DRV_VERSION "0.1"
struct packet_type brcm_packet_type;
// 回调函数,
int brcm_skb_recv(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *ptype,
struct net_device *orig_dev)
{
// 本机回环报文不打印
if (strcmp(dev->name, "lo"))
{
printk(KERN_INFO "device name is %s\n", dev->name);
struct sk_buff *sb = skb;
struct ethhdr *eth;
eth = eth_hdr(sb);
printk(KERN_INFO "SRC MAC: %pM\n",ð->h_source);
printk(KERN_INFO "DST MAC: %pM\n",ð->h_dest);
printk(KERN_INFO "MAC protocol: %04x\n",ntohs(eth->h_proto));
printk(KERN_INFO "Date length = %d\n",sb->len);
}
kfree_skb(skb);
return NET_RX_DROP;
}
// 可以直接声明一个静态 packet_type 变量并进行赋值,但这种方式下,等式右边不能为函数或表达式。
/*
static struct packet_type brcm_packet_type __read_mostly = {
.type = __constant_htons(ETH_P_ALL),
.func = brcm_skb_recv, // 回调函数
};
*/
// 模块加载函数
static int __init brcm_proto_init(void)
{
brcm_packet_type.type = __constant_htons(ETH_P_ALL);
brcm_packet_type.func = brcm_skb_recv;
// brcm_packet_type.dev = dev_get_by_name(&init_net, "eth0"); // 可以指定回调函数生效的网卡,默认为NULL,即全部网卡。
dev_add_pack(&brcm_packet_type); // 注册
return 0;
}
// 模块卸载函数
static void __exit brcm_cleanup_module(void)
{
dev_remove_pack(&brcm_packet_type); // 注销
}
module_init(brcm_proto_init);
module_exit(brcm_cleanup_module);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
/*
<NetDevice.h>
struct packet_type {
__be16 type; // This is really htons(ether_type).
struct net_device *dev; // NULL is wildcarded here
int (*func) (struct sk_buff *,
struct net_device *,
struct packet_type *,
struct net_device *);
void (*list_func) (struct list_head *,
struct packet_type *,
struct net_device *);
bool (*id_match)(struct packet_type *ptype,
struct sock *sk);
void *af_packet_priv;
struct list_head list;
};
*/
来源:CSDN
作者:安倍逸清
链接:https://blog.csdn.net/qq_31329469/article/details/103820465