内核开发交流群 745510310 欢迎加入学习
利用netfilter的框架实现对arp报文的处理,这里只是打印arp报文信息,更多的处理可以在此基础上实现。
arp 首部封装格式:
不同版本内核头文件可能不一样带来编译出错问题,可以参考这篇博客https://blog.csdn.net/fuyuande/article/details/79429441 更新一下内核。
源码如下:
/*
* Description : print arp packet info
* Date : 20180331
* Author : fuyuande
* Note : Kernel version 3.4.39
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LOG(fmt,arg...) printk("[%s %d] "fmt,__FUNCTION__,__LINE__,##arg)
/* arp内容 */
#pragma pack(push,1) /* 字节对齐 */
struct arp_info {
unsigned char src[ETH_ALEN];
__be32 srcip;
unsigned char dst[ETH_ALEN];
__be32 dstip;
};
#pragma pack(pop)
#define IP1(addr) ((unsigned char *)&addr)[0]
#define IP2(addr) ((unsigned char *)&addr)[1]
#define IP3(addr) ((unsigned char *)&addr)[2]
#define IP4(addr) ((unsigned char *)&addr)[3]
static unsigned int arp_input_hook(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct ethhdr * ethh = NULL;
/* 获取L2层首部 */
ethh = eth_hdr(skb);
if(ethh == NULL)
{
return NF_ACCEPT;
}
/* 打印网络层协议类型 */
LOG(" L3 type :%x \r\n",ethh->h_proto);
return NF_ACCEPT;
}
static unsigned int arp_output_hook(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct arphdr *arph = NULL; /* arp首部 */
struct arp_info *arpinfo = NULL;
arph = arp_hdr(skb); /* 获取arp首部 */
if(arph == NULL)
{
LOG("Weird! arp header null \r\n");
return NF_ACCEPT;
}
/* 打印arp首部信息 */
LOG(" arp info :\r\n"
"-------------\r\n"
"arp hw type :%x \r\n"
"arp pro type :%x \r\n"
"arp hln :%d\r\n"
"arp plen:%d\r\n"
"arp ops :%d\r\n"
"-------------\r\n",
ntohs(arph->ar_hrd),ntohs(arph->ar_pro),arph->ar_hln,arph->ar_pln,ntohs(arph->ar_op));
/* 打印mac地址信息 */
arpinfo = (unsigned char *)(arph + 1);
LOG("\n-------------\r\n"
"mac : %x:%x:%x:%x:%x:%x \r\n"
"sip : %d:%d:%d:%d \r\n"
"dmac : %x:%x:%x:%x:%x:%x \r\n"
"dip : %d:%d:%d:%d \r\n"
"-------------\r\n",
arpinfo->src[0],arpinfo->src[1],arpinfo->src[2],arpinfo->src[3],arpinfo->src[4],arpinfo->src[5],
IP1(arpinfo->srcip),IP2(arpinfo->srcip),IP3(arpinfo->srcip),IP4(arpinfo->srcip),
arpinfo->dst[0],arpinfo->dst[1],arpinfo->dst[2],arpinfo->dst[3],arpinfo->dst[4],arpinfo->dst[5],
IP1(arpinfo->dstip),IP2(arpinfo->dstip),IP3(arpinfo->dstip),IP4(arpinfo->dstip));
return NF_ACCEPT;
}
struct nf_hook_ops arp_hook_ops[] ={
{
.hook = arp_input_hook, /* 输入arp钩子函数*/
.pf = NFPROTO_ARP, /* 协议类型 */
.hooknum = NF_ARP_IN, /* arp input 链*/
.priority = 0, /* 优先级 */
},
{
.hook = arp_output_hook, /* 输出arp钩子函数 */
.pf = NFPROTO_ARP, /* 协议类型 */
.hooknum = NF_ARP_OUT, /* arp output 链 */
.priority = 0, /* 优先级 */
},
{}
};
static int __init arp_hook_init(void)
{
/* 注册netfilter钩子 */
nf_register_hooks(arp_hook_ops,ARRAY_SIZE(arp_hook_ops));
return 0;
}
static void __exit arp_hook_exit(void)
{
/* 注销netfilter钩子 */
nf_unregister_hooks(arp_hook_ops,ARRAY_SIZE(arp_hook_ops));
return ;
}
module_init(arp_hook_init)
module_exit(arp_hook_exit)
MODULE_LICENSE("GPL");
Makefile:
obj-m := arphook.o
PWD :=$(shell pwd)
KERNEL_DIR :="/usr/src/linux-headers-3.4.39-030439-generic/"
modules:
$(MAKE) -C $(KERNEL_DIR) M=${PWD} modules
clean:
@rm *.ko *.mod.c *.o Modu* modu*
在内核3.4.39版本上可以直接执行如下命令编译、加载
#编译模块
sudo make
#加载模块
sudo insmod arphook.ko
#卸载模块
sudo rmmod arphook.ko
效果如下:
一开始钩子函数注册在PF_INET上,没有抓到ARP报文,后来查了查,发现协议注册错了,更改成NFPROTO_ARP就可以。