#!/bin/bash # DNS 同步脚本 # 比较 FTP 根目录的 dns.conf 和本地的 dns.conf,如果有变化则同步到 /etc/resolv.conf set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 日志函数 - 输出到 stderr 避免影响函数返回值 log_info() { echo -e "${BLUE}[INFO]${NC} $1" >&2 } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" >&2 } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" >&2 } log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2 } # 获取脚本所在目录 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LOCAL_DNS_CONF="/opt/argus-metric/dns.conf" REMOTE_DNS_CONF_URL="" RESOLV_CONF="/etc/resolv.conf" LOG_FILE="/opt/argus-metric/.dns_sync.log" # 从环境变量或配置文件获取 FTP 服务器信息 get_ftp_config() { # 优先从环境变量获取配置 log_info "获取 FTP 配置信息..." # 如果环境变量中没有设置,则尝试从配置文件读取 if [[ -z "$FTP_SERVER" || -z "$FTP_USER" || -z "$FTP_PASSWORD" ]]; then local config_file="$SCRIPT_DIR/config.env" if [[ -f "$config_file" ]]; then log_info "从配置文件读取 FTP 配置: $config_file" source "$config_file" fi else log_info "使用环境变量中的 FTP 配置" fi # 设置默认值(如果环境变量和配置文件都没有设置) FTP_SERVER="${FTP_SERVER:-localhost}" FTP_USER="${FTP_USER:-ftpuser}" FTP_PASSWORD="${FTP_PASSWORD:-ZGClab1234!}" # 构建远程 DNS 配置文件 URL REMOTE_DNS_CONF_URL="ftp://${FTP_USER}:${FTP_PASSWORD}@${FTP_SERVER}/dns.conf" log_info "FTP 配置来源: ${FTP_CONFIG_SOURCE:-环境变量/配置文件}" } # 下载远程 DNS 配置文件 download_remote_dns_conf() { local temp_file="/tmp/dns.conf.remote.$$" log_info "从 FTP 服务器下载 DNS 配置文件..." log_info "远程地址: $REMOTE_DNS_CONF_URL" log_info "FTP 服务器: $FTP_SERVER" log_info "FTP 用户: $FTP_USER" # 先测试 FTP 连接 log_info "测试 FTP 连接..." if curl -u "${FTP_USER}:${FTP_PASSWORD}" -sfI "ftp://${FTP_SERVER}/" >/dev/null 2>&1; then log_success "FTP 服务器连接成功" else log_error "无法连接到 FTP 服务器: $FTP_SERVER" log_error "请检查:" log_error " 1. FTP 服务器是否运行" log_error " 2. 网络连接是否正常" log_error " 3. 服务器地址是否正确" return 1 fi # 测试 dns.conf 文件是否存在 log_info "检查远程 dns.conf 文件是否存在..." if curl -u "${FTP_USER}:${FTP_PASSWORD}" -sfI "ftp://${FTP_SERVER}/dns.conf" >/dev/null 2>&1; then log_success "远程 dns.conf 文件存在" else log_error "远程 dns.conf 文件不存在或无法访问" log_error "请检查 FTP 服务器根目录下是否有 dns.conf 文件" return 1 fi # 尝试下载文件 log_info "开始下载 dns.conf 文件..." if curl -u "${FTP_USER}:${FTP_PASSWORD}" -sf "ftp://${FTP_SERVER}/dns.conf" -o "$temp_file" 2>/dev/null; then log_success "远程 DNS 配置文件下载成功" echo "$temp_file" else log_error "下载 dns.conf 文件失败" log_error "尝试手动测试命令:" log_error " curl -u ${FTP_USER}:${FTP_PASSWORD} ftp://${FTP_SERVER}/dns.conf" rm -f "$temp_file" return 1 fi } # 比较两个文件是否相同 compare_files() { local file1="$1" local file2="$2" if [[ ! -f "$file1" || ! -f "$file2" ]]; then return 1 fi # 使用 diff 比较文件内容 if diff -q "$file1" "$file2" >/dev/null 2>&1; then return 0 # 文件相同 else return 1 # 文件不同 fi } # 将 DNS 配置添加到 /etc/resolv.conf 开头 update_resolv_conf() { local dns_conf_file="$1" log_info "更新 /etc/resolv.conf 文件..." # 创建临时文件 local temp_resolv="/tmp/resolv.conf.$$" # 将 dns.conf 内容转换为 nameserver 添加到临时文件开头 while IFS= read -r line; do # 跳过空行和注释 [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue # 验证 IP 格式 if [[ "$line" =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; then echo "nameserver $line" >> "$temp_resolv" log_info "添加 DNS 到临时文件: $line" else log_warning "跳过无效 DNS: $line" fi done < "$dns_conf_file" # 将原 resolv.conf 内容追加到临时文件后面 if [[ -f "$RESOLV_CONF" ]]; then cat "$RESOLV_CONF" >> "$temp_resolv" fi # 判断是否是 root if [[ $(id -u) -eq 0 ]]; then # root 直接写入 tee "$RESOLV_CONF" < "$temp_resolv" >/dev/null chmod 644 "$RESOLV_CONF" else # 非 root 尝试使用 sudo if command -v sudo >/dev/null 2>&1; then sudo tee "$RESOLV_CONF" < "$temp_resolv" >/dev/null sudo chmod 644 "$RESOLV_CONF" else log_error "非 root 用户且系统未安装 sudo,无法更新 /etc/resolv.conf" rm -f "$temp_resolv" exit 1 fi fi # 清理临时文件 rm -f "$temp_resolv" log_success "/etc/resolv.conf 已更新" } # 记录同步日志 log_sync() { local message="$1" local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo "[$timestamp] $message" >> "$LOG_FILE" } # 主函数 main() { log_info "开始 DNS 同步检查..." log_sync "DNS 同步检查开始" # 确保系统目录存在 mkdir -p "/opt/argus-metric" # 获取 FTP 配置 get_ftp_config # 检查本地 DNS 配置文件是否存在 if [[ ! -f "$LOCAL_DNS_CONF" ]]; then log_warning "本地 DNS 配置文件不存在: $LOCAL_DNS_CONF" log_warning "将下载远程配置文件并更新系统 DNS 设置" # 下载远程配置文件 if remote_file=$(download_remote_dns_conf); then # 复制到本地 cp "$remote_file" "$LOCAL_DNS_CONF" log_success "远程 DNS 配置文件已保存到本地" # 更新 resolv.conf update_resolv_conf "$LOCAL_DNS_CONF" log_sync "首次同步完成,DNS 配置已更新" # 清理临时文件 rm -f "$remote_file" else log_error "无法下载远程 DNS 配置文件,同步失败" log_sync "同步失败:无法下载远程配置文件" exit 1 fi else log_info "本地 DNS 配置文件存在: $LOCAL_DNS_CONF" # 下载远程配置文件进行比较 if remote_file=$(download_remote_dns_conf); then # 比较文件 if compare_files "$LOCAL_DNS_CONF" "$remote_file"; then log_info "DNS 配置文件无变化,无需更新" log_sync "DNS 配置文件无变化" else log_info "检测到 DNS 配置文件有变化,开始同步..." log_sync "检测到 DNS 配置文件变化,开始同步" # 更新本地配置文件 cp "$remote_file" "$LOCAL_DNS_CONF" log_success "本地 DNS 配置文件已更新" # 更新 resolv.conf update_resolv_conf "$LOCAL_DNS_CONF" log_sync "DNS 配置同步完成" fi # 清理临时文件 rm -f "$remote_file" else log_error "无法下载远程 DNS 配置文件,跳过本次同步" log_sync "同步失败:无法下载远程配置文件" exit 1 fi fi log_success "DNS 同步检查完成" log_sync "DNS 同步检查完成" } # 脚本入口 if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi