您的位置:首页 > 运维架构 > Linux

使用netfilter框架处理ARP报文

2018-03-31 19:19 896 查看
利用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 <linux/init.h>
#include <linux/module.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_arp.h>

#define LOG(fmt,arg...) printk("[%s %d] "fmt,__FUNCTION__,__LINE__,##arg)

#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;
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;
struct arp_info *arpinfo = NULL;
arph = arp_hdr(skb);

if(arph == NULL)
{
LOG("Weird! arp header null \r\n");
return NF_ACCEPT;
}

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));
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,
.pf = NFPROTO_ARP,
.hooknum = NF_ARP_IN,
.priority = 0,
},
{
.hook = arp_output_hook,
.pf = NFPROTO_ARP,
.hooknum = NF_ARP_OUT,
.priority = 0,
},
{}
};

static int __init arp_hook_init(void)
{
nf_register_hooks(arp_hook_ops,ARRAY_SIZE(arp_hook_ops));
return 0;
}

static void __exit arp_hook_exit(void)
{
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就可以。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息