本文目录导读:

#!/bin/bash
# 自动更新ARP缓存脚本
# 功能:通过主动ping局域网内所有可能的主机,更新本地ARP缓存
# 适用环境:Linux/Unix with bash, ping, arp, ip (可选)
# 注意:需要root权限执行(如需修改内核参数或清空缓存)
# ========== 配置参数 ==========
# 局域网的网络前缀(请根据实际网络修改)
NETWORK_PREFIX="192.168.1"
# 起始IP和结束IP,建议扫描整个C类网段(1-254)以确保完整更新
START_IP=1
END_IP=254
# 并行ping的并发数(避免过载,建议20-50)
PARALLEL_LIMIT=50
# 是否清空现有ARP缓存再更新(0=不清空,1=清空)
FLUSH_CACHE=0
# 日志文件路径(留空则不记录日志)
LOG_FILE="/var/log/arp_update.log"
# ========== 函数定义 ==========
# 日志记录函数
log_message() {
local message="$1"
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
if [ -n "$LOG_FILE" ]; then
echo "[${timestamp}] ${message}" >> "$LOG_FILE"
fi
# 同时输出到终端(可选)
# echo "[${timestamp}] ${message}"
}
# 检查必要命令
check_requirements() {
local missing=0
for cmd in ping arp; do
if ! command -v "$cmd" &> /dev/null; then
echo "错误:未找到命令 '$cmd',请先安装。"
missing=1
fi
done
# 可选命令 ip
if ! command -v ip &> /dev/null; then
echo "警告:未找到 'ip' 命令,将使用 'arp' 命令操作缓存。"
fi
if [ $missing -eq 1 ]; then
exit 1
fi
}
# 清空ARP缓存(需要root权限)
flush_arp_cache() {
if [ "$FLUSH_CACHE" -eq 1 ]; then
log_message "开始清空ARP缓存..."
# 尝试使用ip命令(较新系统)或arp命令(较旧系统)
if command -v ip &> /dev/null; then
# 使用ip命令删除所有动态和非本地条目
# 注意:不要删除网关或重要的静态条目(可根据需要调整)
ip neigh flush all 2>/dev/null || {
# 更精细的方法:仅清除指定网络接口的条目(示例eth0)
# ip neigh flush dev eth0 2>/dev/null
log_message "警告:ip neigh flush 失败,尝试逐一删除。"
}
else
# 使用arp命令逐个删除(较慢)
arp -n | grep -v "incomplete" | awk '{print $1}' | while read ip; do
arp -d "$ip" 2>/dev/null
done
fi
log_message "ARP缓存已清空。"
else
log_message "跳过清空ARP缓存。"
fi
}
# 执行ping并更新ARP(单个IP)
ping_and_update() {
local ip="$1"
# 发送1个ping包,超时1秒,安静模式
# 如果ping通,系统会自动更新ARP缓存(如果条目已存在则会刷新)
ping -c 1 -W 1 "$ip" &> /dev/null
# 返回值为0表示通,非0表示不通(不影响脚本继续)
return $?
}
# 并行ping管理(使用后台进程控制并发)
parallel_ping() {
local ip_list=("$@")
local count=0
local total=${#ip_list[@]}
for ip in "${ip_list[@]}"; do
# 在后台执行ping
(ping_and_update "$ip") &
# 控制并发数
((count++))
if [ $((count % PARALLEL_LIMIT)) -eq 0 ]; then
wait # 等待当前批次完成
fi
done
wait # 等待所有剩余后台任务完成
}
# ========== 主程序 ==========
# 检查是否为root(清空缓存需要,如果不清空则不需要)
if [ "$FLUSH_CACHE" -eq 1 ] && [ "$(id -u)" -ne 0 ]; then
echo "错误:清空ARP缓存需要root权限,请使用sudo执行。"
exit 1
fi
log_message "========== ARP缓存更新开始 =========="
log_message "网络前缀: ${NETWORK_PREFIX}.${START_IP}-${END_IP}"
log_message "并发数: ${PARALLEL_LIMIT}"
log_message "清空缓存: ${FLUSH_CACHE}"
# 检查依赖
check_requirements
# 清空缓存(可选)
flush_arp_cache
# 生成IP列表
ip_list=()
for i in $(seq "$START_IP" "$END_IP"); do
ip_list+=("${NETWORK_PREFIX}.${i}")
done
total_ips=${#ip_list[@]}
log_message "开始并行ping ${total_ips} 个IP地址..."
# 执行并行ping
parallel_ping "${ip_list[@]}"
log_message "所有IP ping完成。"
# 显示当前的ARP缓存(可选)
if command -v arp &> /dev/null; then
echo "----------------------------------------"
echo "当前ARP缓存内容(动态条目):"
# 显示非incomplete的条目
arp -n -a 2>/dev/null || arp -a 2>/dev/null
echo "----------------------------------------"
elif command -v ip &> /dev/null; then
echo "当前ARP缓存(neigh):"
ip neigh show 2>/dev/null
fi
log_message "========== ARP缓存更新完成 =========="
# 如果记录了日志,提示日志位置
if [ -n "$LOG_FILE" ]; then
echo "日志已记录至: ${LOG_FILE}"
fi
exit 0
脚本使用说明
-
配置网络参数:脚本顶部的
NETWORK_PREFIX变量需修改为您所在局域网的网络号(如168.1、0.0等)。START_IP和END_IP用于定义扫描范围,默认扫描整个C类网段(1-254)。 -
权限要求:
- 如果开启
FLUSH_CACHE=1(清空缓存),则需要使用sudo或root用户执行。 FLUSH_CACHE=0(不清空,仅通过ping更新),则普通用户也可执行,但部分系统可能限制ARP缓存操作。
- 如果开启
-
执行方式:
# 赋予执行权限 chmod +x arp_update.sh # 普通执行(不自动清空缓存) ./arp_update.sh # 如果需要清空缓存并更新(需要sudo) sudo ./arp_update.sh
-
工作机制:
- 脚本通过批量并发
ping局域网内的所有IP地址,只要目标主机存活并响应,操作系统会自动将该主机的IP-MAC对应关系写入或刷新到ARP缓存中。 - 并发数(
PARALLEL_LIMIT)控制了同时发送ping请求的数量,防止网络过载。
- 脚本通过批量并发
-
输出与日志:
- 执行过程中,关键步骤会输出到终端,同时日志会记录到
LOG_FILE指定的路径(默认/var/log/arp_update.log)。 - 脚本执行完毕后会显示当前ARP缓存内容。
- 执行过程中,关键步骤会输出到终端,同时日志会记录到
注意事项
- 网络负载:虽然使用了并发控制,但在大型网络(如超过254个IP)或网络设备性能较差的场景下,快速发送大量ping仍可能造成短暂负载上升,建议在非业务高峰期执行。
- ARP缓存保护:某些系统可能会保护静态ARP条目或网关条目不被轻易刷新,如果遇到特定条目不更新的情况,可能需要单独处理。
- 跨网段更新:该脚本仅能更新本机(运行脚本的机器)的ARP缓存,若要更新网络设备(如交换机、路由器)的ARP表,需使用其他协议(如SNMP)或登录设备操作。
如果您有特定的应用场景(如针对特定IP列表、仅更新某个接口),或需要其他版本的脚本(如Python版),欢迎进一步告知。