ARP请求拦截及响应

一、前言

本文主要是介绍如何对arp请求包进行拦截,并代替系统进行响应。对arp请求进行拦截,需要在驱动中进行,具体代码如下文所示。(本文仅供参考)

二、环境

	OS Ubuntu 20.04.6 LTS
	Linux ubuntu 5.15.0-71-generic

三、源码

驱动代码如下(arp_hook.c):

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAC_arg(x) x[0],x[1],x[2],x[3],x[4],x[5]

 void print_arp_packet(struct sk_buff *skb) {
    struct arphdr *arp;
	unsigned char *arp_ptr;
	__be32 sip, tip;
	unsigned char *sha, *tha;

	arp = (struct arphdr *)skb->data;
	arp_ptr = (unsigned char *)(arp+1);
	
	sha = arp_ptr;
	memcpy(&sip, arp_ptr+ETH_ALEN, 4);
	tha = arp_ptr+ETH_ALEN + 4;
	memcpy(&tip, arp_ptr+ETH_ALEN+4+ETH_ALEN, 4);
	
	printk(KERN_INFO "ARP ar_op=%s sha=%02x:%02x:%02x:%02x:%02x:%02x sip=%pI4 tha=%02x:%02x:%02x:%02x:%02x:%02x tip=%pI4\n", 
		(ntohs(arp->ar_op)==ARPOP_REQUEST ? "Request" : "Response") , MAC_arg(sha),&sip, MAC_arg(tha), &tip);
}

//构建arp响应包
void arp_response(struct sk_buff *skb, const struct nf_hook_state *state){
	struct arphdr *arp = NULL;
    unsigned char *data = NULL;
	unsigned char src_hw[ETH_ALEN] = {0}, dest_hw[ETH_ALEN] = {0};
	__be32 src_ip, dest_ip;

	arp = (struct arphdr *)skb->data;
	data = (unsigned char *)(arp+1);

	//从包中拷贝mac地址等信息
	memcpy(&src_ip, data + ETH_ALEN + 4 + ETH_ALEN, 4); //新包源ip=旧包目的ip
	memcpy(dest_hw, data, ETH_ALEN);	//新包目的MAC=旧包源MAC
	memcpy(&dest_ip, data + ETH_ALEN, 4); //新包目的ip=旧包源ip

	//获取本机mac
	memcpy(src_hw, state->in->dev_addr, ETH_ALEN);

	arp_send(ARPOP_REPLY, ETH_P_ARP, dest_ip, state->in, src_ip, dest_hw, src_hw, dest_hw);
	/*arp_send(int type, int ptype, __be32 dest_ip,
	      struct net_device *dev, __be32 src_ip,
	      const unsigned char *dest_hw, const unsigned char *src_hw,
	      const unsigned char *target_hw)
		  */
}

// 定义钩子函数
static unsigned int arp_hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
    struct ethhdr *eth_header = NULL;
    struct arphdr *arp_header = NULL;
	
	//长度不对直接返回
    if (skb->len < sizeof(struct ethhdr) + sizeof(struct arphdr)) {
		return NF_ACCEPT;
	}

	//获取以太网头部指针
	eth_header = eth_hdr(skb);
    if (htons(ETH_P_ARP) != eth_header->h_proto){
        return NF_ACCEPT;
	}
	
	//判断是否为ARP请求报文
	//(需要注意的是邻居发的针对于网关IP的ARP请求的处理,但正常没有此情况发生,故此处暂时不处理)
	arp_header = arp_hdr(skb);
	if (htons(ARPOP_REQUEST) != arp_header->ar_op) {
		return NF_ACCEPT;
	}
	
	//只处理固定接口名的arp报文
    if (strcmp(skb->dev->name, "enp1s0") == 0)
    {
		print_arp_packet(skb);
		arp_response(skb, state);
		
        return NF_DROP;
    }
	
    return NF_ACCEPT;
}


//定义钩子结构体
struct nf_hook_ops arp_hook = {
	.hook = arp_hook_func,
	.pf = NFPROTO_ARP, 
	.hooknum = NF_ARP,
	.priority = NF_IP_PRI_FIRST
};

static int __init arp_hook_init(void)
{
	nf_register_net_hook(&init_net, &arp_hook);

    printk(KERN_INFO "ARP hook module loaded\n");
    return 0;
}

static void __exit arp_hook_exit(void)
{
    nf_unregister_net_hook(&init_net, &arp_hook);
    printk(KERN_INFO "ARP hook module unloaded\n");
}

module_init(arp_hook_init);
module_exit(arp_hook_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhazha");
MODULE_DESCRIPTION("ARP hook Module");

Makefile如下:

# Makefile for driver

KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

obj-m += arp_hook.o

all: driver

driver:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

运行结果:
运行日志
抓包结果
其它:
加载驱动命令:insmod arp_hook.ko
卸载驱动命令:remod arp_hook
查看驱动是否已经加载:lsmod | grep arp_hook
linux日志查看:tail -f /var/log/syslog
arp表查看命令:arp -a

你可能感兴趣的:(Linux,C/C++,c语言,ARP拦截,ARP欺骗,驱动开发,ARP响应)