这个脚本用于自动更新 ufw(Uncomplicated Firewall)的规则,以允许来自动态域名(如 ddns.net)的 IP 地址访问指定的端口。脚本会周期性地检查域名的 IP 地址,并根据需要添加或删除防火墙规则。

功能

  • 从指定的动态域名获取 IPv4 和 IPv6 地址。
  • 比对当前地址和之前保存的地址,更新 ufw 规则以允许或拒绝访问。
  • 自动记录所有操作到日志文件中。

安装和使用

1. 创建一个文件夹将下列代码保存为update_ufw.sh文件

#!/bin/bash

# 获取脚本文件所在目录的绝对路径
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

# 使用相对路径构建日志文件的路径
LOG_FILE="$SCRIPT_DIR/ufw.log"
DOMAIN="ddns.net"
PORTS="12345,54321"

# 检查和创建日志文件
touch $LOG_FILE
chmod 600 $LOG_FILE

# 初始化上一个 IP 地址
stored_ipv4=""
stored_ipv6=""

# 获取域名的 IPv4 和 IPv6 地址
get_new_ips() {
    new_ipv4=$(dig +short $DOMAIN | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}')
    new_ipv6=$(dig +short AAAA $DOMAIN | grep -Eo '([0-9a-fA-F:]+:+)+[0-9a-fA-F]+')
}

# 更新 UFW 规则
update_ufw_rule() {
    get_new_ips

    if [ -n "$new_ipv4" ] && [ "$new_ipv4" != "$stored_ipv4" ]; then
        delete_rules "$stored_ipv4" "IPv4"
        update_rules "$new_ipv4" "IPv4"
        stored_ipv4=$new_ipv4
    fi

    if [ -n "$new_ipv6" ] && [ "$new_ipv6" != "$stored_ipv6" ]; then
        delete_rules "$stored_ipv6" "IPv6"
        update_rules "$new_ipv6" "IPv6"
        stored_ipv6=$new_ipv6
    fi
}

# 删除规则的函数
delete_rules() {
    local old_ip=$1
    local ip_version=$2

    if [ -n "$old_ip" ]; then
        IFS=',' read -ra port_array <<< "$PORTS"
        for port in "${port_array[@]}"; do
            rule_name="$DOMAIN"
            ufw delete allow proto tcp from $old_ip to any port $port comment "$rule_name" &>> $LOG_FILE
            echo "$(date +"%Y-%m-%d %T") - 已删除 $ip_version 规则: 禁止 $old_ip 访问端口 $port" >> $LOG_FILE
        done
    fi
}

# 更新规则的函数
update_rules() {
    local new_ip=$1
    local ip_version=$2

    IFS=',' read -ra port_array <<< "$PORTS"
    for port in "${port_array[@]}"; do
        rule_name="$DOMAIN"
        ufw allow proto tcp from $new_ip to any port $port comment "$rule_name" &>> $LOG_FILE
        echo "$(date +"%Y-%m-%d %T") - 已更新 $ip_version 规则: 允许 $new_ip 访问端口 $port" >> $LOG_FILE
    done
}

# 添加初始规则的函数
add_initial_ufw_rule() {
    get_new_ips

    if [ -n "$new_ipv4" ] || [ -n "$new_ipv6" ]; then
        IFS=',' read -ra port_array <<< "$PORTS"
        for port in "${port_array[@]}"; do
            rule_name="$DOMAIN"
            if [ -n "$new_ipv4" ]; then
                ufw allow proto tcp from $new_ipv4 to any port $port comment "$rule_name" &>> $LOG_FILE
                echo "$(date +"%Y-%m-%d %T") - 已添加初始 IPv4 规则: 允许 $new_ipv4 访问端口 $port" >> $LOG_FILE
                stored_ipv4=$new_ipv4
            fi
            if [ -n "$new_ipv6" ]; then
                ufw allow proto tcp from $new_ipv6 to any port $port comment "$rule_name" &>> $LOG_FILE
                echo "$(date +"%Y-%m-%d %T") - 已添加初始 IPv6 规则: 允许 $new_ipv6 访问端口 $port" >> $LOG_FILE
                stored_ipv6=$new_ipv6
            fi
        done
    fi
}

# 添加初始规则
add_initial_ufw_rule

# 循环执行更新规则的操作
while true; do
    update_ufw_rule
    sleep 300  # 每 5 分钟检查一次
done

2. 给脚本加权

chmod +x update_ufw.sh

3. 配置脚本变量

编辑update_ufw.sh文件中的以下变量: · DOMAIN:要解析的动态域名(例如 ddns.net) · PORTS:要更新的端口列表(例如 12345,54321)

4. 后台运行该脚本

nohup bash /path/to/update_ufw.sh > /dev/null 2>&1 &

脚本将会后台持续运行,并每隔 5 分钟检查一次 IP 地址是否更新。