#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h>
// 用户配置结构体
typedef struct
{
int enable; // 功能开关 (0=禁用, 1=启用)
int scan_interval; // 扫描周期 (秒)
int entry_timeout; // 条目有效期 (秒)
int packet_interval; // 发包间隔 (毫秒)
uint32_t start_ip; // 起始IP (网络字节序)
uint32_t end_ip; // 结束IP (网络字节序)
} UserConfig;
// 定义结构体标签
typedef struct ArpEntry
{
uint32_t ip; // IP地址 (网络字节序)
uint8_t mac[6]; // MAC地址
time_t last_seen; // 最后发现时间
struct ArpEntry *next; // 链表指针 (使用结构体标签)
} ArpEntry;
// 全局变量
UserConfig config =
{
.enable = 1, // 默认启用
.scan_interval = 60, // 默认60秒
.entry_timeout = 300, // 默认300秒有效期
.packet_interval = 100, // 默认100毫秒发包间隔
.start_ip = 0, // 初始化为0
.end_ip = 0 // 初始化为0
};
ArpEntry *arp_table = NULL; // ARP缓存表头指针
pthread_mutex_t table_mutex = PTHREAD_MUTEX_INITIALIZER;
// ARP报文结构
struct arp_packet
{
struct ethhdr eth_header;
struct ether_arp arp_data;
};
// 函数声明
void print_config();
void print_arp_table();
void update_arp_entry(uint32_t ip, uint8_t *mac);
void cleanup_expired_entries();
void *arp_table_manager(void *arg);
// 获取本机MAC地址
void get_mac_address(const char *interface, uint8_t *mac)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
struct ifreq ifr;
strncpy(ifr.ifr_name, interface, IFNAMSIZ-1);
if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1)
{
perror("MAC获取失败");
close(fd);
exit(EXIT_FAILURE);
}
memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
close(fd);
}
// 获取本机IP地址
void get_ip_address(const char *interface, uint32_t *ip)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
struct ifreq ifr;
strncpy(ifr.ifr_name, interface, IFNAMSIZ-1);
if (ioctl(fd, SIOCGIFADDR, &ifr) == -1)
{
perror("IP获取失败");
close(fd);
exit(EXIT_FAILURE);
}
*ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
close(fd);
}
// 创建ARP套接字
int create_arp_socket()
{
int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
if (sock < 0)
{
perror("Socket创建失败");
exit(EXIT_FAILURE);
}
return sock;
}
// 发送ARP请求
void send_arp_request(int sock, const char *interface,
uint32_t src_ip, uint8_t *src_mac,
uint32_t target_ip)
{
struct arp_packet packet;
struct sockaddr_ll addr;
// 填充以太网帧头
memset(packet.eth_header.h_dest, 0xFF, ETH_ALEN); // 广播地址
memcpy(packet.eth_header.h_source, src_mac, ETH_ALEN);
packet.eth_header.h_proto = htons(ETH_P_ARP);
// 填充ARP数据
packet.arp_data.arp_hrd = htons(ARPHRD_ETHER);
packet.arp_data.arp_pro = htons(ETH_P_IP);
packet.arp_data.arp_hln = ETH_ALEN;
packet.arp_data.arp_pln = 4;
packet.arp_data.arp_op = htons(ARPOP_REQUEST);
memcpy(packet.arp_data.arp_sha, src_mac, ETH_ALEN);
memcpy(&packet.arp_data.arp_spa, &src_ip, 4);
memset(packet.arp_data.arp_tha, 0x00, ETH_ALEN); // 目标MAC未知
memcpy(&packet.arp_data.arp_tpa, &target_ip, 4);
// 配置接口
memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_ifindex = if_nametoindex(interface);
addr.sll_halen = ETH_ALEN;
memcpy(addr.sll_addr, packet.eth_header.h_dest, ETH_ALEN);
// 发送数据包
if (sendto(sock, &packet, sizeof(packet), 0,
(struct sockaddr*)&addr, sizeof(addr)) < 0)
{
perror("ARP请求发送失败");
}
}
// 接收ARP响应
void receive_arp_response(int sock, uint8_t *src_mac)
{
struct arp_packet recv_packet;
struct sockaddr_ll addr;
socklen_t addr_len = sizeof(addr);
// 设置接收超时
struct timeval tv = {.tv_sec = 1, .tv_usec = 0};
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
while (1)
{
ssize_t len = recvfrom(sock, &recv_packet, sizeof(recv_packet), 0,
(struct sockaddr*)&addr, &addr_len);
if (len < 0) break; // 超时或错误
// 检查是否为ARP响应
if (ntohs(recv_packet.eth_header.h_proto) == ETH_P_ARP
&& ntohs(recv_packet.arp_data.arp_op) == ARPOP_REPLY)
{
// 验证发送方MAC是否匹配
if (memcmp(recv_packet.arp_data.arp_tha, src_mac, ETH_ALEN) == 0)
{
uint32_t resp_ip = *(uint32_t*)recv_packet.arp_data.arp_spa;
uint8_t *resp_mac = recv_packet.arp_data.arp_sha;
// 检查是否在目标范围内
uint32_t net_resp = ntohl(resp_ip);
uint32_t net_start = ntohl(config.start_ip);
uint32_t net_end = ntohl(config.end_ip);
if (net_resp >= net_start && net_resp <= net_end)
{
// 更新ARP表
update_arp_entry(resp_ip, resp_mac);
}
}
}
}
}
// 更新ARP条目
void update_arp_entry(uint32_t ip, uint8_t *mac)
{
pthread_mutex_lock(&table_mutex);
ArpEntry *current = arp_table;
ArpEntry *prev = NULL;
int is_new = 1;
time_t now = time(NULL);
// 查找是否已存在
while (current != NULL)
{
if (current->ip == ip)
{
// 更新现有条目
memcpy(current->mac, mac, 6);
current->last_seen = now;
is_new = 0;
break;
}
prev = current;
current = current->next;
}
if (is_new)
{
// 创建新条目
ArpEntry *new_entry = malloc(sizeof(ArpEntry));
new_entry->ip = ip;
memcpy(new_entry->mac, mac, 6);
new_entry->last_seen = now;
new_entry->next = arp_table;
arp_table = new_entry;
// 打印新主机信息
char ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ip, ip_str, INET_ADDRSTRLEN);
printf("\n[NEW] Host active: %s [MAC: %02X:%02X:%02X:%02X:%02X:%02X]",
ip_str, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
pthread_mutex_unlock(&table_mutex);
}
// 清理过期条目
void cleanup_expired_entries()
{
pthread_mutex_lock(&table_mutex);
time_t now = time(NULL);
ArpEntry *current = arp_table;
ArpEntry *prev = NULL;
ArpEntry *next = NULL;
while (current != NULL)
{
next = current->next; // 保存下一个节点
if (difftime(now, current->last_seen) > config.entry_timeout)
{
// 打印过期信息
char ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, ¤t->ip, ip_str, INET_ADDRSTRLEN);
printf("[EXPIRED] Removing entry: %s\n", ip_str);
// 移除条目
if (prev == NULL)
{
arp_table = next;
}
else
{
prev->next = next;
}
free(current);
}
else
{
prev = current;
}
current = next; // 移动到下一个节点
}
pthread_mutex_unlock(&table_mutex);
}
// ARP表管理线程
void *arp_table_manager(void *arg)
{
(void)arg; // 避免未使用参数警告
while (1)
{
sleep(10); // 每10秒检查一次
cleanup_expired_entries();
}
return NULL;
}
// 打印配置信息
void print_config()
{
char start_ip[INET_ADDRSTRLEN];
char end_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &config.start_ip, start_ip, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &config.end_ip, end_ip, INET_ADDRSTRLEN);
printf("\n=== 当前配置 ===\n");
printf("功能状态: %s\n", config.enable ? "启用" : "禁用");
printf("扫描周期: %d 秒\n", config.scan_interval);
printf("条目有效期: %d 秒\n", config.entry_timeout);
printf("发包间隔: %d 毫秒\n", config.packet_interval);
printf("起始IP: %s\n", start_ip);
printf("结束IP: %s\n", end_ip);
printf("================\n");
}
// 打印ARP表
void print_arp_table()
{
pthread_mutex_lock(&table_mutex);
ArpEntry *current = arp_table;
int count = 0;
printf("\n=== ARP表 ===\n");
while (current != NULL) {
char ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, ¤t->ip, ip_str, INET_ADDRSTRLEN);
char time_str[20];
struct tm *tm_info = localtime(¤t->last_seen);
strftime(time_str, 20, "%Y-%m-%d %H:%M:%S", tm_info);
printf("%-15s %02X:%02X:%02X:%02X:%02X:%02X 最后发现: %s\n",
ip_str,
current->mac[0], current->mac[1], current->mac[2],
current->mac[3], current->mac[4], current->mac[5],
time_str);
current = current->next;
count++;
}
printf("总条目: %d\n", count);
printf("=======================\n");
pthread_mutex_unlock(&table_mutex);
}
// 定时扫描函数
void arp_scan()
{
uint8_t src_mac[6];
uint32_t src_ip;
const char *interface = "ens37";
get_mac_address(interface, src_mac);
get_ip_address(interface, &src_ip);
int sock = create_arp_socket();
// 启动ARP表管理线程
pthread_t manager_thread;
pthread_create(&manager_thread, NULL, arp_table_manager, NULL);
while (1)
{
if (config.enable)
{
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
char time_str[20];
strftime(time_str, 20, "%Y-%m-%d %H:%M:%S", tm_info);
printf("\n[%s] 开始ARP扫描 (范围: %u-%u)",
time_str,
ntohl(config.start_ip), ntohl(config.end_ip));
// 扫描指定IP范围
uint32_t start = ntohl(config.start_ip);
uint32_t end = ntohl(config.end_ip);
for (uint32_t ip = start; ip <= end; ip++)
{
if (ip == ntohl(src_ip)) continue; // 跳过本机
uint32_t target_ip = htonl(ip);
send_arp_request(sock, interface, src_ip, src_mac, target_ip);
// 按配置的发包间隔等待
if (config.packet_interval > 0)
{
usleep(config.packet_interval * 1000);
}
}
// 接收响应
receive_arp_response(sock, src_mac);
// 打印当前ARP表
print_arp_table();
}
// 按配置的扫描周期等待
sleep(config.scan_interval);
}
}
// 开始扫描
void arp_start()
{
// 设置用户配置
config.enable = 1;
config.scan_interval = 2; // 60秒扫描周期
config.entry_timeout = 300; // 300秒有效期
config.packet_interval = 100; // 100毫秒发包间隔
// 设置扫描范围: 192.168.1.100 - 192.168.1.200
inet_pton(AF_INET, "192.168.63.65", &config.start_ip);
inet_pton(AF_INET, "192.168.63.75", &config.end_ip);
// 打印初始配置
print_config();
arp_scan();
}
int main()
{
arp_start();
return 0;
}
修改该代码 使其包含以下函数功能
set_arp_config(设置功能开关、扫描周期、有效期、发包间隔、起始IP、结束IP地址)
get_arp_config(获取功能开关、扫描周期、有效期、发包间隔、起始IP、结束IP地址)
start_scan(开始一次扫描)
stop_scan(停止扫描)
get_scan_status(扫描状态)
get_scan_result(获取最近一次的扫描结果)
clear_result(清除历史结果)
最新发布