#include "arp_scanner.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/if_packet.h>
#include <time.h>
#include <errno.h>
#include "json_api.h"
// 从二进制文件加载配置
int load_config(arp_config_t *config)
{
if (config == NULL)
{
fprintf(stderr, "错误: 配置指针为空\n");
return -1;
}
// 使用ds_read读取配置
ds_read(ARPD_CONFIG_PATH, config, sizeof(arp_config_t));
return 0;
}
S32 arp_scanner_init()
{
memset(&g_scanner, 0, sizeof(arp_scanner_t));
// 创建原始套接字
g_scanner.raw_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
if (g_scanner.raw_socket < 0)
{
perror("socket");
return -1;
}
// 初始化互斥锁
if (pthread_mutex_init(&g_scanner.lock, NULL) != 0)
{
close(&g_scanner.raw_socket);
return -1;
}
// 从配置文件加载配置
if (load_config(&g_scanner.config) != 0)
{
// 加载失败时使用默认值
gscanner.config.enabled = FALSE;
gscanner.config.scan_interval = 60;
gscanner.config.validity_period = 300;
gscanner.config.packet_interval = 100;
gscanner.config.start_ip = ip_to_int("192.168.1.100");
gscanner.config.end_ip = ip_to_int("192.168.1.200");
// 默认网络接口
strcpy(gscanner.config.interface, "eth0");
fprintf(stderr, "Using default configuration\n");
}
return 0;
}
S32 arp_scanner_start(void)
{
pthread_mutex_lock(&g_scanner.lock);
g_scanner.scanning = TRUE;
g_scanner.stop_requested = FALSE;
pthread_mutex_unlock(&g_scanner.lock);
// 创建扫描线程
pthread_t scan_thread;
if (pthread_create(&scan_thread, NULL, scan_thread_func, NULL) != 0)
{
perror("pthread_create");
return -1;
}
return 0;
}
int arp_scanner_stop(arp_scanner_t *scanner)
{
if (!scanner)
return -1;
pthread_mutex_lock(&scanner->lock);
scanner->stop_requested = TRUE;
pthread_mutex_unlock(&scanner->lock);
return 0;
}
int arp_scanner_cleanup(arp_scanner_t *scanner)
{
if (!scanner)
return -1;
arp_scanner_stop(scanner);
if (scanner->raw_socket >= 0)
{
close(scanner->raw_socket);
}
pthread_mutex_destroy(&scanner->lock);
return 0;
}
void *scan_thread_func(void *arg)
{
arp_scanner_t *scanner = (arp_scanner_t *)arg;
while (!scanner->stop_requested)
{
arp_scanner_scan(scanner);
// 等待扫描间隔
sleep(scanner->config.scan_interval);
}
pthread_mutex_lock(&scanner->lock);
scanner->scanning = FALSE;
pthread_mutex_unlock(&scanner->lock);
return NULL;
}
int arp_scanner_scan(arp_scanner_t *scanner)
{
if (!scanner || !scanner->config.enabled)
return -1;
struct ifreq ifr;
strcpy(ifr.ifr_name, scanner->config.interface);
// 获取接口索引
if (ioctl(scanner->raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
perror("ioctl");
return -1;
}
// 绑定到接口
struct sockaddr_ll saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sll_family = AF_PACKET;
saddr.sll_ifindex = ifr.ifr_ifindex;
saddr.sll_protocol = htons(ETH_P_ARP);
if (bind(scanner->raw_socket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind");
return -1;
}
// 发送ARP请求
for (uint32_t ip = scanner->config.start_ip;
ip <= scanner->config.end_ip && !scanner->stop_requested;
ip++)
{
arp_scanner_send_arp_request(scanner, ip);
usleep(scanner->config.packet_interval * 1000);
}
// 处理ARP回复
arp_scanner_process_reply(scanner);
// 清理过期条目
arp_scanner_clean_old_entries(scanner);
scanner->last_scan_time = time(NULL);
return 0;
}
int arp_scanner_send_arp_request(arp_scanner_t *scanner, uint32_t target_ip)
{
struct ifreq ifr;
strcpy(ifr.ifr_name, scanner->config.interface);
// 获取接口MAC地址
if (ioctl(scanner->raw_socket, SIOCGIFHWADDR, &ifr) < 0)
{
perror("ioctl");
return -1;
}
unsigned char *src_mac = (unsigned char *)ifr.ifr_hwaddr.sa_data;
// 获取接口IP地址
if (ioctl(scanner->raw_socket, SIOCGIFADDR, &ifr) < 0)
{
perror("ioctl");
return -1;
}
struct sockaddr_in *ipaddr = (struct sockaddr_in *)&ifr.ifr_addr;
uint32_t src_ip = ipaddr->sin_addr.s_addr;
// 构建ARP请求包
arp_packet_t packet;
// 以太网头部
memset(packet.eth_header.h_dest, 0xFF, 6); // 广播地址
memcpy(packet.eth_header.h_source, src_mac, 6);
packet.eth_header.h_proto = htons(ETH_P_ARP);
// ARP头部
packet.arp_header.ar_hrd = htons(ARPHRD_ETHER);
packet.arp_header.ar_pro = htons(ETH_P_IP);
packet.arp_header.ar_hln = 6;
packet.arp_header.ar_pln = 4;
packet.arp_header.ar_op = htons(ARPOP_REQUEST);
memcpy(packet.sender_mac, src_mac, 6);
memcpy(packet.sender_ip, &src_ip, 4);
memset(packet.target_mac, 0, 6);
memcpy(packet.target_ip, &target_ip, 4);
// 发送包
struct sockaddr_ll dest;
memset(&dest, 0, sizeof(dest));
dest.sll_family = AF_PACKET;
dest.sll_ifindex = ifr.ifr_ifindex;
dest.sll_halen = ETH_ALEN;
memset(dest.sll_addr, 0xFF, ETH_ALEN);
ssize_t sent = sendto(scanner->raw_socket, &packet, sizeof(packet), 0,
(struct sockaddr *)&dest, sizeof(dest));
return (sent == sizeof(packet)) ? 0 : -1;
}
int arp_scanner_process_reply(arp_scanner_t *scanner)
{
if (!scanner)
{
return -1;
}
fd_set readfds;
struct timeval tv;
int ret;
int max_fd = scanner->raw_socket;
// 设置超时时间为2秒,用于等待ARP回复
tv.tv_sec = 2;
tv.tv_usec = 0;
// 循环处理所有可用的ARP回复
while (1)
{
FD_ZERO(&readfds);
FD_SET(scanner->raw_socket, &readfds);
ret = select(max_fd + 1, &readfds, NULL, NULL, &tv);
if (ret < 0)
{
if (errno == EINTR)
{
// 被信号中断,继续等待
continue;
}
perror("select");
break;
}
else if (ret == 0)
{
// 超时,没有更多数据
break;
}
if (FD_ISSET(scanner->raw_socket, &readfds))
{
arp_packet_t packet;
struct sockaddr_ll saddr;
socklen_t saddr_len = sizeof(saddr);
// 接收ARP数据包
ssize_t received = recvfrom(scanner->raw_socket, &packet, sizeof(packet), 0,
(struct sockaddr *)&saddr, &saddr_len);
if (received < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
continue;
}
perror("recvfrom");
continue;
}
// 检查接收到的数据包长度
if (received < (ssize_t)(sizeof(struct ethhdr) + sizeof(struct arphdr)))
{
// 数据包太短,不是有效的ARP包
continue;
}
// 验证以太网类型是否为ARP
if (ntohs(packet.eth_header.h_proto) != ETH_P_ARP)
{
continue;
}
// 验证ARP硬件类型为以太网
if (ntohs(packet.arp_header.ar_hrd) != ARPHRD_ETHER)
{
continue;
}
// 验证ARP协议类型为IP
if (ntohs(packet.arp_header.ar_pro) != ETH_P_IP)
{
continue;
}
// 检查是否是ARP回复
if (ntohs(packet.arp_header.ar_op) == ARPOP_REPLY)
{
// 提取发送者IP和MAC地址
uint32_t sender_ip;
memcpy(&sender_ip, packet.sender_ip, 4);
char mac_str[MAX_MAC_LEN];
mac_to_string(packet.sender_mac, mac_str);
// 检查IP是否在扫描范围内
if (sender_ip >= scanner->config.start_ip &&
sender_ip <= scanner->config.end_ip)
{
// 添加到ARP条目表
arp_scanner_add_entry(scanner, sender_ip, mac_str);
// 打印调试信息
char ip_str[MAX_IP_LEN];
int_to_ip(sender_ip, ip_str);
printf("Received ARP reply from %s [%s]\n", ip_str, mac_str);
}
}
}
}
return 0;
}
int arp_scanner_add_entry(arp_scanner_t *scanner, uint32_t ip, const char *mac)
{
if (!scanner || !mac)
{
return -1;
}
pthread_mutex_lock(&scanner->lock);
time_t now = time(NULL);
int found_index = -1;
BOOL is_new_host = FALSE;
// 检查是否已存在该IP的条目
for (int i = 0; i < scanner->entry_count; i++)
{
if (scanner->entries[i].ip == ip)
{
found_index = i;
break;
}
}
if (found_index >= 0)
{
// 更新现有条目
strncpy(scanner->entries[found_index].mac, mac, MAX_MAC_LEN - 1);
scanner->entries[found_index].mac[MAX_MAC_LEN - 1] = '\0';
scanner->entries[found_index].last_seen = now;
}
else
{
// 添加新条目
if (scanner->entry_count < MAX_ARP_ENTRIES)
{
arp_entry_t *entry = &scanner->entries[scanner->entry_count];
entry->ip = ip;
strncpy(entry->mac, mac, MAX_MAC_LEN - 1);
entry->mac[MAX_MAC_LEN - 1] = '\0';
entry->last_seen = now;
entry->first_seen = now;
scanner->entry_count++;
is_new_host = TRUE;
}
else
{
// ARP表已满,找到最旧的条目替换
time_t oldest_time = now;
int oldest_index = 0;
for (int i = 0; i < scanner->entry_count; i++)
{
if (scanner->entries[i].last_seen < oldest_time)
{
oldest_time = scanner->entries[i].last_seen;
oldest_index = i;
}
}
// 替换最旧的条目
arp_entry_t *entry = &scanner->entries[oldest_index];
entry->ip = ip;
strncpy(entry->mac, mac, MAX_MAC_LEN - 1);
entry->mac[MAX_MAC_LEN - 1] = '\0';
entry->last_seen = now;
entry->first_seen = now;
is_new_host = TRUE;
}
}
pthread_mutex_unlock(&scanner->lock);
// 如果是新发现的主机,打印到串口
if (is_new_host)
{
char ip_str[MAX_IP_LEN];
int_to_ip(ip, ip_str);
printf("NEW HOST: IP=%s, MAC=%s\n", ip_str, mac);
}
return 0;
}
void arp_scanner_clean_old_entries(arp_scanner_t *scanner)
{
if (!scanner)
{
return;
}
pthread_mutex_lock(&scanner->lock);
time_t now = time(NULL);
int write_index = 0;
for (int read_index = 0; read_index < scanner->entry_count; read_index++)
{
if (now - scanner->entries[read_index].last_seen <= scanner->config.validity_period)
{
// 条目未过期,保留
if (write_index != read_index)
{
scanner->entries[write_index] = scanner->entries[read_index];
}
write_index++;
}
else
{
// 条目过期,打印日志
char ip_str[MAX_IP_LEN];
int_to_ip(scanner->entries[read_index].ip, ip_str);
printf("EXPIRED: IP=%s, MAC=%s\n", ip_str, scanner->entries[read_index].mac);
}
}
// 更新条目计数
int expired_count = scanner->entry_count - write_index;
scanner->entry_count = write_index;
pthread_mutex_unlock(&scanner->lock);
if (expired_count > 0)
{
printf("Cleaned %d expired ARP entries\n", expired_count);
}
}
void arp_scanner_print_results(arp_scanner_t *scanner)
{
if (!scanner)
{
return;
}
pthread_mutex_lock(&scanner->lock);
printf("\n=== ARP Scan Results ===\n");
printf("Total hosts: %d\n", scanner->entry_count);
printf("Last scan: %s", ctime(&scanner->last_scan_time));
printf("-----------------------------------------------\n");
printf("IP Address\t\tMAC Address\t\tFirst Seen\t\tLast Seen\n");
printf("-----------------------------------------------\n");
for (int i = 0; i < scanner->entry_count; i++)
{
char ip_str[MAX_IP_LEN];
int_to_ip(scanner->entries[i].ip, ip_str);
char first_seen_str[64];
char last_seen_str[64];
struct tm *tm_info;
tm_info = localtime(&scanner->entries[i].first_seen);
strftime(first_seen_str, sizeof(first_seen_str), "%Y-%m-%d %H:%M:%S", tm_info);
tm_info = localtime(&scanner->entries[i].last_seen);
strftime(last_seen_str, sizeof(last_seen_str), "%Y-%m-%d %H:%M:%S", tm_info);
printf("%-15s\t%s\t%s\t%s\n",
ip_str,
scanner->entries[i].mac,
first_seen_str,
last_seen_str);
}
printf("-----------------------------------------------\n");
pthread_mutex_unlock(&scanner->lock);
}
int arp_scanner_remove_entry(arp_scanner_t *scanner, uint32_t ip)
{
if (!scanner)
{
return -1;
}
pthread_mutex_lock(&scanner->lock);
int found_index = -1;
// 查找要删除的条目
for (int i = 0; i < scanner->entry_count; i++)
{
if (scanner->entries[i].ip == ip)
{
found_index = i;
break;
}
}
if (found_index >= 0)
{
// 移动后续条目覆盖要删除的条目
for (int i = found_index; i < scanner->entry_count - 1; i++)
{
scanner->entries[i] = scanner->entries[i + 1];
}
scanner->entry_count--;
char ip_str[MAX_IP_LEN];
int_to_ip(ip, ip_str);
printf("Removed ARP entry: %s\n", ip_str);
}
pthread_mutex_unlock(&scanner->lock);
return (found_index >= 0) ? 0 : -1;
}
// 工具函数
uint32_t ip_to_int(const char *ip)
{
if (!ip)
{
return 0;
}
struct in_addr addr;
if (inet_pton(AF_INET, ip, &addr) != 1)
{
fprintf(stderr, "Invalid IP address: %s\n", ip);
return 0;
}
return addr.s_addr;
}
void int_to_ip(uint32_t ip_int, char *ip_str)
{
if (!ip_str)
{
return;
}
struct in_addr addr;
addr.s_addr = ip_int;
inet_ntop(AF_INET, &addr, ip_str, MAX_IP_LEN);
}
void mac_to_string(const unsigned char *mac, char *mac_str)
{
if (!mac || !mac_str)
{
return;
}
snprintf(mac_str, MAX_MAC_LEN, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
把所有函数都统一成全局变量模式,并且整个应用是单线程循环而不是多线程的应用