#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)
{
// 加载失败时使用默认值
g_scanner.config.enabled = FALSE;
g_scanner.config.scan_interval = 60;
g_scanner.config.validity_period = 300;
g_scanner.config.packet_interval = 100;
g_scanner.config.start_ip = ip_to_int("192.168.1.100");
g_scanner.config.end_ip = ip_to_int("192.168.1.200");
// 默认网络接口
strcpy(g_scanner.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);
return 0;
}
int arp_scanner_stop(void)
{
pthread_mutex_lock(&g_scanner.lock);
g_scanner.stop_requested = TRUE;
pthread_mutex_unlock(&g_scanner.lock);
return 0;
}
int arp_scanner_cleanup(void)
{
arp_scanner_stop();
if (g_scanner.raw_socket >= 0)
{
close(g_scanner.raw_socket);
}
pthread_mutex_destroy(&g_scanner.lock);
return 0;
}
int arp_scanner_scan(void)
{
if (!g_scanner.config.enabled)
return -1;
struct ifreq ifr;
strcpy(ifr.ifr_name, g_scanner.config.interface);
// 获取接口索引
if (ioctl(g_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(g_scanner.raw_socket, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind");
return -1;
}
// 发送ARP请求
for (uint32_t ip = g_scanner.config.start_ip;
ip <= g_scanner.config.end_ip && !g_scanner.stop_requested;
ip++)
{
arp_scanner_send_arp_request(ip);
usleep(g_scanner.config.packet_interval * 1000);
}
// 处理ARP回复
arp_scanner_process_reply();
// 清理过期条目
arp_scanner_clean_old_entries();
g_scanner.last_scan_time = time(NULL);
return 0;
}
int arp_scanner_send_arp_request(uint32_t target_ip)
{
struct ifreq ifr;
strcpy(ifr.ifr_name, g_scanner.config.interface);
// 获取接口MAC地址
if (ioctl(g_scanner.raw_socket, SIOCGIFHWADDR, &ifr) < 0)
{
perror("ioctl");
return -1;
}
unsigned char *src_mac = (unsigned char *)ifr.ifr_hwaddr.sa_data;
// 获取接口IP地址
if (ioctl(g_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(g_scanner.raw_socket, &packet, sizeof(packet), 0,
(struct sockaddr *)&dest, sizeof(dest));
return (sent == sizeof(packet)) ? 0 : -1;
}
int arp_scanner_process_reply(void)
{
fd_set readfds;
struct timeval tv;
int ret;
int max_fd = g_scanner.raw_socket;
// 设置超时时间为2秒,用于等待ARP回复
tv.tv_sec = 2;
tv.tv_usec = 0;
// 循环处理所有可用的ARP回复
while (1)
{
FD_ZERO(&readfds);
FD_SET(g_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(g_scanner.raw_socket, &readfds))
{
arp_packet_t packet;
struct sockaddr_ll saddr;
socklen_t saddr_len = sizeof(saddr);
// 接收ARP数据包
ssize_t received = recvfrom(g_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 >= g_scanner.config.start_ip &&
sender_ip <= g_scanner.config.end_ip)
{
// 添加到ARP条目表
arp_scanner_add_entry(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(uint32_t ip, const char *mac)
{
if (!mac)
{
return -1;
}
pthread_mutex_lock(&g_scanner.lock);
time_t now = time(NULL);
int found_index = -1;
BOOL is_new_host = FALSE;
// 检查是否已存在该IP的条目
for (int i = 0; i < g_scanner.entry_count; i++)
{
if (g_scanner.entries[i].ip == ip)
{
found_index = i;
break;
}
}
if (found_index >= 0)
{
// 更新现有条目
strncpy(g_scanner.entries[found_index].mac, mac, MAX_MAC_LEN - 1);
g_scanner.entries[found_index].mac[MAX_MAC_LEN - 1] = '\0';
g_scanner.entries[found_index].last_seen = now;
}
else
{
// 添加新条目
if (g_scanner.entry_count < MAX_ARP_ENTRIES)
{
arp_entry_t *entry = &g_scanner.entries[g_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;
g_scanner.entry_count++;
is_new_host = TRUE;
}
else
{
// ARP表已满,找到最旧的条目替换
time_t oldest_time = now;
int oldest_index = 0;
for (int i = 0; i < g_scanner.entry_count; i++)
{
if (g_scanner.entries[i].last_seen < oldest_time)
{
oldest_time = g_scanner.entries[i].last_seen;
oldest_index = i;
}
}
// 替换最旧的条目
arp_entry_t *entry = &g_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(&g_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(void)
{
pthread_mutex_lock(&g_scanner.lock);
time_t now = time(NULL);
int write_index = 0;
for (int read_index = 0; read_index < g_scanner.entry_count; read_index++)
{
if (now - g_scanner.entries[read_index].last_seen <= g_scanner.config.validity_period)
{
// 条目未过期,保留
if (write_index != read_index)
{
g_scanner.entries[write_index] = g_scanner.entries[read_index];
}
write_index++;
}
else
{
// 条目过期,打印日志
char ip_str[MAX_IP_LEN];
int_to_ip(g_scanner.entries[read_index].ip, ip_str);
printf("EXPIRED: IP=%s, MAC=%s\n", ip_str, g_scanner.entries[read_index].mac);
}
}
// 更新条目计数
int expired_count = g_scanner.entry_count - write_index;
g_scanner.entry_count = write_index;
pthread_mutex_unlock(&g_scanner.lock);
if (expired_count > 0)
{
printf("Cleaned %d expired ARP entries\n", expired_count);
}
}
int arp_scanner_remove_entry(uint32_t ip)
{
pthread_mutex_lock(&g_scanner.lock);
int found_index = -1;
// 查找要删除的条目
for (int i = 0; i < g_scanner.entry_count; i++)
{
if (g_scanner.entries[i].ip == ip)
{
found_index = i;
break;
}
}
if (found_index >= 0)
{
// 移动后续条目覆盖要删除的条目
for (int i = found_index; i < g_scanner.entry_count - 1; i++)
{
g_scanner.entries[i] = g_scanner.entries[i + 1];
}
g_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(&g_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]);
}
将上述文件的函数封装到int arpd_start_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param)
{
// 创建响应JSON对象
context->res_obj = jso_new_obj();
if (NULL == context->res_obj)
{
DS_ERROR("Create new json object failed.");
context->error_code = SLP_ESYSTEM;
return ERROR;
}
// 关键修改:启动前先执行初始化
int init_result = arp_scanner_init();
if (init_result != 0)
{
jso_add_string(context->res_obj, "status", "error");
jso_add_string(context->res_obj, "message", "Scanner initialization failed");
return ERROR;
}
// 启动扫描
int start_result = arp_scanner_start();
if (start_result == 0)
{
jso_add_string(context->res_obj, "status", "success");
jso_add_string(context->res_obj, "message", "Scan started successfully");
// 添加扫描配置信息
pthread_mutex_lock(&g_scanner.lock);
jso_add_bool(context->res_obj, "enabled", g_scanner.config.enabled);
jso_add_int(context->res_obj, "scan_interval", g_scanner.config.scan_interval);
jso_add_int(context->res_obj, "validity_period", g_scanner.config.validity_period);
char start_ip_str[MAX_IP_LEN], end_ip_str[MAX_IP_LEN];
int_to_ip(g_scanner.config.start_ip, start_ip_str);
int_to_ip(g_scanner.config.end_ip, end_ip_str);
jso_add_string(context->res_obj, "start_ip", start_ip_str);
jso_add_string(context->res_obj, "end_ip", end_ip_str);
jso_add_string(context->res_obj, "interface", g_scanner.config.interface);
pthread_mutex_unlock(&g_scanner.lock);
}
else
{
jso_add_string(context->res_obj, "status", "error");
jso_add_string(context->res_obj, "message", "Failed to start scan");
}
return start_result;
}
// 停止扫描
// 停止扫描
int arpd_stop_scan(struct _DS_HANDLE_CONTEXT *context, JSON_OBJPTR param)
{
// 创建响应JSON对象
context->res_obj = jso_new_obj();
if (NULL == context->res_obj)
{
DS_ERROR("Create new json object failed.");
context->error_code = SLP_ESYSTEM;
return ERROR;
}
// 获取当前扫描状态
pthread_mutex_lock(&g_scanner.lock);
BOOL was_scanning = g_scanner.scanning;
int entry_count = g_scanner.entry_count;
time_t last_scan_time = g_scanner.last_scan_time;
pthread_mutex_unlock(&g_scanner.lock);
// 执行停止操作
int stop_result = arp_scanner_stop();
// 构建响应
if (stop_result == 0)
{
jso_add_string(context->res_obj, "status", "success");
jso_add_string(context->res_obj, "action", was_scanning ? "Scan stopped" : "No active scan to stop");
// 添加扫描结果统计
jso_add_bool(context->res_obj, "was_scanning", was_scanning);
jso_add_int(context->res_obj, "entry_count", entry_count);
// 添加时间信息
char last_scan_str[32];
if (last_scan_time > 0)
{
format_timestamp(last_scan_time, last_scan_str);
jso_add_string(context->res_obj, "last_scan_time", last_scan_str);
}
else
{
jso_add_string(context->res_obj, "last_scan_time", "Never scanned");
}
// 添加配置信息
pthread_mutex_lock(&g_scanner.lock);
jso_add_bool(context->res_obj, "enabled", g_scanner.config.enabled);
jso_add_int(context->res_obj, "scan_interval", g_scanner.config.scan_interval);
pthread_mutex_unlock(&g_scanner.lock);
}
else
{
jso_add_string(context->res_obj, "status", "error");
jso_add_string(context->res_obj, "message", "Failed to stop scan");
jso_add_int(context->res_obj, "error_code", stop_result);
}
return stop_result;
}中,arpd_start_scan需要真正实现启动扫描并扫描的过程