141 lines
5.8 KiB
C
141 lines
5.8 KiB
C
/*
|
||
扫描所有局域网IP地址的MAC信息
|
||
发ARP请求报文,通过for循环组成同一个网段的不同IP地址,发送出来,并接收响应的ARP报文信息
|
||
*/
|
||
#include <arpa/inet.h>
|
||
#include <netinet/in.h>
|
||
#include <netinet/ether.h>
|
||
#include <netpacket/packet.h>
|
||
#include <sys/ioctl.h>
|
||
#include <net/if.h> // ifreq
|
||
#include <unistd.h>
|
||
#include <string.h> // bzero
|
||
#include <stdio.h>
|
||
#include <pthread.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <fcntl.h>
|
||
|
||
// 发送原始数据报
|
||
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name);
|
||
|
||
void *recv_packetdata(void *arg)
|
||
{
|
||
// 创建原始套接字
|
||
int sock_fd = *((int *)arg);
|
||
|
||
while (1)
|
||
{
|
||
// 接链接层的数据报文
|
||
unsigned char buf[1518] = "";
|
||
int len = recvfrom(sock_fd, buf, sizeof(buf), 0, NULL, NULL);
|
||
if (len < 18)
|
||
{
|
||
perror("recvfrom");
|
||
continue;
|
||
}
|
||
|
||
// 拆解MAC数据报文
|
||
unsigned char dst_mac[18] = "";
|
||
unsigned char src_mac[18] = "";
|
||
unsigned short mac_type = ntohs(*((unsigned short *)(buf + 12)));
|
||
sprintf(dst_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
|
||
sprintf(src_mac, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||
buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
|
||
if (mac_type == 0x0806) // 当类型为ARP时
|
||
{
|
||
printf("------ARP数据报-----\n");
|
||
unsigned char src_ip[16] = "";
|
||
unsigned char dst_ip[16] = "";
|
||
unsigned short op = ntohs(*((unsigned short *)(buf + 20)));
|
||
if (op == 2) // 只显示ARP应答的数据
|
||
{
|
||
// inet_ntop函数被用于将存储在buf + 28位置的二进制IPv4地址转换为字符串表示形式,并将结果存储在src_ip变量中。
|
||
inet_ntop(AF_INET, (unsigned int *)(buf + 28), src_ip, 16);
|
||
inet_ntop(AF_INET, (unsigned int *)(buf + 38), dst_ip, 16);
|
||
printf("%s(%s) -> %s(%s)\n", src_mac, src_ip, dst_mac, dst_ip);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
int main(int argc, char const *argv[])
|
||
{
|
||
|
||
// 创建原始套接字 // htons(ETH_P_ALL)的作用是将以太网协议号转换为网络字节序,以便在创建原始套接字时使用正确的协议号。
|
||
int sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||
if (sock_fd < 0)
|
||
{
|
||
perror("raw socket");
|
||
return -1;
|
||
}
|
||
|
||
// 创建接收数据报的线程
|
||
pthread_t tid;
|
||
pthread_create(&tid, NULL, recv_packetdata, &sock_fd);
|
||
// pthread_detach(tid);
|
||
|
||
// 组织ARP应答报文(如果是ARP欺骗,则源MAC地址可以修改为全0或修改为其他用于伪装的MAC地址)
|
||
uint32_t src_ip = inet_addr("10.12.156.204");
|
||
// 扫描所有网内的IP的MAC地址
|
||
for (int i = 150; i < 253; i++)
|
||
// for (int i = 2; i < 255; i++)
|
||
{
|
||
unsigned char dst_ip_[16] = "";
|
||
sprintf(dst_ip_, "10.12.156.%d", i);
|
||
// inet_addr函数被用于将点分十进制表示的IPv4地址转换为32位无符号整数的网络字节序表示。
|
||
uint32_t dst_ip = inet_addr(dst_ip_);
|
||
unsigned char *src_ip_pointer = (unsigned char *)&src_ip; // 定义源地址ip指针
|
||
unsigned char *dst_ip_pointer = (unsigned char *)&dst_ip;
|
||
unsigned char buf[] = {
|
||
// 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 用于广播, 常用于扫描MAC地址
|
||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*目标MAC*/
|
||
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /*源MAC*/
|
||
0x08, 0x06, /*帧类型(ARP)*/
|
||
0x00, 0x01, /*硬件类型(以太网)*/
|
||
0x08, 0x00, /*协议类型(IP)*/
|
||
0x06, 0x04, /*硬件地址长度(6字节)和协议地址长度(4字节)*/
|
||
0x00, 0x01, /*操作类型(ARP请求)*/
|
||
0x00, 0x0c, 0x29, 0x85, 0xcc, 0x67, /*发送方MAC*/
|
||
src_ip_pointer[0], src_ip_pointer[1], src_ip_pointer[2], src_ip_pointer[3], /*发送方IP*/
|
||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*目标MAC*/
|
||
dst_ip_pointer[0], dst_ip_pointer[1], dst_ip_pointer[2], dst_ip_pointer[3] /*目标IP*/
|
||
};
|
||
|
||
// 单播(发送ARP请求): 通过网卡名查找网卡索引, 选择合适的网卡索引, 发送数据
|
||
ssize_t len = send_datapacket(sock_fd, buf, sizeof(buf), "ens38");
|
||
if (len > 0)
|
||
{
|
||
printf("发送ARP应答报文成功\n");
|
||
}
|
||
usleep(1000 * 1000);
|
||
}
|
||
|
||
pthread_join(tid, NULL);
|
||
close(sock_fd);
|
||
return 0;
|
||
}
|
||
|
||
ssize_t send_datapacket(int fd, unsigned char *buf, ssize_t buf_size, const char *ether_name)
|
||
{
|
||
// 1. 获取网络接口类型(通过网卡名查找网卡索引)
|
||
struct ifreq ether_req;
|
||
bzero(ðer_req, sizeof(ether_req));
|
||
strncpy(ether_req.ifr_name, ether_name, IF_NAMESIZE); // # define ifr_name ifr_ifrn.ifrn_name
|
||
|
||
if (ioctl(fd, SIOCGIFINDEX, ðer_req) == -1)
|
||
{
|
||
perror("ioctl");
|
||
return -1;
|
||
}
|
||
|
||
// 2. 选择发送数据的网络接口索引(选择合适的网卡索引)
|
||
struct sockaddr_ll sll;
|
||
bzero(&sll, sizeof(sll));
|
||
sll.sll_ifindex = ether_req.ifr_ifindex; // # define ifr_ifindex ifr_ifru.ifru_ivalue
|
||
|
||
// 3. 发送数据
|
||
ssize_t len = sendto(fd, buf, buf_size, 0, (struct sockaddr *)&sll, sizeof(sll));
|
||
return len;
|
||
} |