[C++] 纯文本查看 复制代码
/*!
arp: (Address Resolution Protocal)地址解析协议
功能:通过ip地址获取mac地址
报文格式:
----------------------------------------------------------------------------------------
| 6 6 2 2 2 1 1 2 6 4 6 4 |
|目的mac 源mac 帧类型 硬件类型 协议类型 硬件地址长度 协议地址长度 op 源mac 源ip 目的mac 目的ip|
----------------------------------------------------------------------------------------
目的mac: FF:FF:FF:FF:FF:FF
源mac: 本机mac
帧类型: 0x0800(IP)--0x0806(ARP)--0x8035(RARP)
硬件类型: 以太网地址(1)
协议类型: 0x0800(IP)
硬件地址长度: 6
协议地址长度: 4
op: ARP请求(1)--ARP应答(2)--RARP请求(3)--RARP应答(4)
源mac: 本机mac
源ip: 本机ip
目的mac: 0
目的ip: 目的ip地址
*/
#include <iostream>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <unistd.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <cstring>
#include <sys/ioctl.h>
#include <pthread.h>
/*!
* @brief: 通过arp获取指定网段ip、mac地址
* @param: 原始套接字
* @return: NULL
*/
void *send_arp(void *arg)
{
int sock_raw_fd = *(int *)arg;
unsigned char send_data[1024] =
{
// 以太网报文
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // 目的mac
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 源mac
0x08, 0x06, // 帧类型
// ARP报文
0x00, 0x01, // 硬件类型
0x08, 0x00, // 协议类型
0x06, 0x04, // 硬件地址长度 协议地址长度
0x00, 0x01, // op
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 源mac
0x00, 0x00, 0x00, 0x00, // 源ip
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 目的mac
0x00, 0x00, 0x00, 0x00 // 目的ip
};
struct sockaddr_ll sll; // #include <netpacket/packet.h>
struct ifreq ethreq; // #include <net/if.h>
strncpy(ethreq.ifr_ifrn.ifrn_name, "enp4s0", IF_NAMESIZE);
ioctl(sock_raw_fd, SIOCGIFINDEX, (char *)ereq);
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifru.ifru_ivalue;
sendto(sock_raw_fd, send_data, 42, 0, (struct sockaddr *)&sll, sizeof(sll));
// 获取本机ip
ioctl(sock_raw_fd, SIOCGIFADDR, (char *)ereq);
unsigned int num = ntohl(((struct sockaddr_in *)(ereq.ifr_ifru.ifru_addr))->sin_addr.s_addr);
for (int i = 0; i < 4; i++)
send_data[31 - i] = num >> (8 * i) & 0xff;
char ip[16]{};
sprintf(ip, "%d:%d:%d:%d",
send_data[28], send_data[29], send_data[30], send_data[31]);
printf("%s\n", ip);
// 获取本机mac
ioctl(sock_raw_fd, SIOCGIFHWADDR, (char *)ereq);
for (int i = 0; i < 6; i++)
send_data[6 + i] = send_data[22 + i] = (unsigned char)ethreq.ifr_ifru.ifru_hwaddr.sa_data[i];
char mac[18]{};
sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
send_data[22], send_data[23], send_data[24], send_data[25], send_data[26], send_data[27]);
printf("%s\n", mac);
unsigned int network[10]{};
unsigned char inbuf[32]{};
printf("请输入输入一个指定网段:\n");
fgets((char *)inbuf, sizeof(inbuf), stdin);
sscanf((char *)inbuf, "%d.%d.%d.%d", &network[0], &network[1], &network[2], &network[3]);
for (int i = 0; i < 4; i++)
send_data[38 + i] = network[i];
for (int i = 1; i <= 254; i++)
{
send_data[41] = i;
sendto(sock_raw_fd, send_data, 42, 0, (struct sockaddr *)&sll, sizeof(sll));
}
return NULL;
}
int main(void)
{
int sock_raw_fd = -1;
sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
pthread_t send_arp_thread;
pthread_create(&send_arp_thread, NULL, send_arp, (void *)&sock_raw_fd);
usleep(100000);
unsigned char recv_data[1024];
for (int i = 1; i <= 254; i++)
{
bzero(recv_data, sizeof(recv_data));
recvfrom(sock_raw_fd, recv_data, sizeof(recv_data), 0, NULL, NULL);
if (recv_data[12] == 0x08 &&
recv_data[13] == 0x06 &&
recv_data[21] == 0x02)
{
char mac[18]{};
char ip[16]{};
sprintf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
recv_data[22], recv_data[23], recv_data[24], recv_data[25], recv_data[26], recv_data[27]);
sprintf(ip, "%d:%d:%d:%d",
recv_data[28], recv_data[29], recv_data[30], recv_data[31]);
printf("ip:%s--mac:%s\n", ip, mac);
}
}
pthread_detach(send_arp_thread);
return 0;
}