Reviewed-on: #17 Reviewed-by: sundapeng <sundp@mail.zgclab.edu.cn> Reviewed-by: xuxt <xuxt@zgclab.edu.cn>
107 lines
2.7 KiB
Bash
107 lines
2.7 KiB
Bash
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
WATCH_DIR="/private/argus/etc"
|
||
ZONE_DB="/private/argus/bind/db.argus.com"
|
||
LOCKFILE="/var/lock/argus_dns_sync.lock"
|
||
BACKUP_DIR="/private/argus/bind/.backup"
|
||
SLEEP_SECONDS=10
|
||
RELOAD_SCRIPT="/usr/local/bin/reload-bind9.sh" # 这里放你已有脚本的路径
|
||
|
||
mkdir -p "$(dirname "$LOCKFILE")" "$BACKUP_DIR"
|
||
BACKUP_UID="${ARGUS_BUILD_UID:-2133}"
|
||
BACKUP_GID="${ARGUS_BUILD_GID:-2015}"
|
||
chown -R "$BACKUP_UID:$BACKUP_GID" "$BACKUP_DIR" 2>/dev/null || true
|
||
|
||
is_ipv4() {
|
||
local ip="$1"
|
||
[[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || return 1
|
||
IFS='.' read -r a b c d <<<"$ip"
|
||
for n in "$a" "$b" "$c" "$d"; do
|
||
(( n >= 0 && n <= 255 )) || return 1
|
||
done
|
||
return 0
|
||
}
|
||
|
||
get_current_ip() {
|
||
local name="$1"
|
||
sed -n -E "s/^${name}[[:space:]]+IN[[:space:]]+A[[:space:]]+([0-9.]+)[[:space:]]*$/\1/p" "$ZONE_DB" | head -n1
|
||
}
|
||
|
||
upsert_record() {
|
||
local name="$1"
|
||
local new_ip="$2"
|
||
local ts
|
||
ts="$(date +%Y%m%d-%H%M%S)"
|
||
local changed=0
|
||
|
||
cp -a "$ZONE_DB" "$BACKUP_DIR/db.argus.com.$ts.bak"
|
||
chown "$BACKUP_UID:$BACKUP_GID" "$BACKUP_DIR/db.argus.com.$ts.bak" 2>/dev/null || true
|
||
|
||
local cur_ip
|
||
cur_ip="$(get_current_ip "$name" || true)"
|
||
|
||
if [[ -z "$cur_ip" ]]; then
|
||
# Ensure the file ends with a newline before adding new record
|
||
if [[ -s "$ZONE_DB" ]] && [[ $(tail -c1 "$ZONE_DB" | wc -l) -eq 0 ]]; then
|
||
echo "" >> "$ZONE_DB"
|
||
fi
|
||
printf "%-20s IN A %s\n" "$name" "$new_ip" >> "$ZONE_DB"
|
||
echo "[ADD] ${name} -> ${new_ip}"
|
||
changed=1
|
||
elif [[ "$cur_ip" != "$new_ip" ]]; then
|
||
awk -v n="$name" -v ip="$new_ip" '
|
||
{
|
||
if ($1==n && $2=="IN" && $3=="A") {
|
||
printf "%-20s IN A %s\n", n, ip
|
||
} else {
|
||
print
|
||
}
|
||
}
|
||
' "$ZONE_DB" > "${ZONE_DB}.tmp" && mv "${ZONE_DB}.tmp" "$ZONE_DB"
|
||
echo "[UPDATE] ${name}: ${cur_ip} -> ${new_ip}"
|
||
changed=1
|
||
else
|
||
echo "[SKIP] ${name} unchanged (${new_ip})"
|
||
fi
|
||
|
||
if [[ $changed -eq 1 ]]; then
|
||
return 0
|
||
fi
|
||
return 1
|
||
}
|
||
|
||
while true; do
|
||
exec 9>"$LOCKFILE"
|
||
if flock -n 9; then
|
||
shopt -s nullglob
|
||
NEED_RELOAD=0
|
||
|
||
for f in "$WATCH_DIR"/*.argus.com; do
|
||
base="$(basename "$f")"
|
||
name="${base%.argus.com}"
|
||
ip="$(grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' "$f" | tail -n1 || true)"
|
||
|
||
if [[ -z "$ip" ]] || ! is_ipv4 "$ip"; then
|
||
echo "[WARN] $f 未找到有效 IPv4,跳过"
|
||
continue
|
||
fi
|
||
|
||
if upsert_record "$name" "$ip"; then
|
||
NEED_RELOAD=1
|
||
fi
|
||
done
|
||
|
||
if [[ $NEED_RELOAD -eq 1 ]]; then
|
||
echo "[INFO] 检测到 db.argus.com 变更,执行 reload-bind9.sh"
|
||
bash "$RELOAD_SCRIPT"
|
||
fi
|
||
|
||
flock -u 9
|
||
else
|
||
echo "[INFO] 已有同步任务在运行,跳过本轮"
|
||
fi
|
||
|
||
sleep "$SLEEP_SECONDS"
|
||
done
|