打开/关闭搜索
搜索
打开/关闭菜单
54
691
62
1945
md5.pw
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
上传文件
打开/关闭外观设置菜单
通知
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
user-interface-preferences
个人工具
登录
请求账号
查看“︁使用搬瓦工api操作nftables实现更新白名单ip”︁的源代码
来自md5.pw
分享此页面
更多语言
查看
阅读
查看源代码
查看历史
associated-pages
页面
讨论
更多操作
←
使用搬瓦工api操作nftables实现更新白名单ip
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
== '''<big>请注意不要泄漏API_Key 任何时候都不要泄露 防止服务器和API被盗用 应当在安全的设备上使用API 防止API_Key被盗取</big>''' == <big>'''根据可实时知晓ip变化的办法不同 您需要的工具也不相同..最多需要多一台本地的Linux服务器(不是防火墙所在的那个服务器哦)'''</big> == 使用前准备 == === 切换到root或有高权限的用户 === 输入<code>whoami</code>(蓝色输出)或者查看 @之前的名字(绿色框)就是使用的用户 [[File:Whoami2.png|border]] 如果是root就是root就可以了 如果不是 [[File:Suroot.png|border]] 你输入 <code>nft list ruleset</code> 或者 <code>sudo nft list ruleset</code> 输入你的密码 和上图一样 说明没权限…. 尝试切换到root账户 输入 <code>su -</code> 然后输入 '''root 用户'''的密码。输入的密码不会显示 输入好后按回车就行 变成root就说明成功了 [[File:Suroot2.png|border]] === 防火墙部分 === 输入 <code>sudo nft list ruleset</code> [[File:Nftlist.png|border]] 你的防火墙中应该有一个空白的链 专用户白名单 然后在含有粉色框框(主要是含有hook input就行)代码的链中 jump这个链 另外先不要改成policy drop; 如果没有链的话 如何创建链 <code>sudo nft add chain inet my_firewall allowed_ip</code> 请根据自己的表的类型inet 表的名字 my_firewall 自行修改哦 allowed_ip可以改成自己想要的名字 比如sudo <code>nft add chain inet my_firewall whiteip</code> 要先有链 才能jump 链的名字 如何添加一条jump allowed_ip 规则呢 <code>sudo nft add rule inet my_firewall my_input jump allowed_ip</code> 还是一样要修改成自己的表的类型 表的名字 刚刚创建的链的名字 要把这个jump allowed_ip 添加到 含有粉色代码的chain里面也就是(my_input) === 服务器部分 === '''创建一个脚本 用 API 调用这个脚本就好了 免去了 API中过多的指令''' '''如果你是从 [[服务器安全-防火墙 nftables]] 那文章一步一步 没有修改防火墙的表 链 的话 直接复制代码框的全部内容 粘贴到ssh里面 按回车 文件就创建好了''' 如果你修改了防火墙的表和链的名字 或不是根据 那篇文章来的 请修改下面代码中的内容 根据自身情况修改 只需要修改=后面 “” 双引号里面的内容 [[File:Nftlist3.png|border]] * TABLE_NAME="my_firewall" ** 这个是表的名字 蓝色框框 * CHAIN_NAME="allowed_ip" ** 这个是链的名字 绿色框框 这个链的名字一定不是你 包含 hook input 粉色这一行的那个链..因为会被清空..然后就会可能导致防火墙规则混乱…一定要是另外一个专门的链 * FAMILY="inet" ** 这个是表类型 红色框框 '''示例''' [[File:Nftlist3-1.png|border]] 如示例中的图就要改成这样的 CHAIN_NAME="allowed_mobile" TABLE_NAME="filter" FAMILY="inet" 不变 如果是table ip filter就把FAMILY="inet" 改成 FAMILY="ip" 这里还有一个位置需要输入 <code>ls /root/update_fw.sh</code> '''检查这个目录是否有一个叫update_fw.sh如果有的话你也需要修改 避免被覆盖''' 上面 蓝色框框的 说明 有存在的同名文件 那你就需要修改 成 > /root/别的文件名.sh那么下文中的所有/root/update_fw.sh都要改成你自己的文件名 下面红色框框说明没有找到这个文件就 不用改名了 直接使用就行 [[File:Catcheckfilehave.png|border]] 在下面的代码框里的对应位置改 可以先复制到记事本上 改完再全选重新复制 粘贴到ssh里面 回车 [[File:Apiconfig.png|border]] '''代码框的脚本如下:'''<syntaxhighlight lang="bash"> cat << 'EOF' > /root/update_fw.sh #!/bin/bash # --- 用户配置区 --- TABLE_NAME="my_firewall" CHAIN_NAME="allowed_ip" FAMILY="inet" # --- 获取参数并剔除所有空格 --- IP1=$(echo "$1" | tr -d '[:space:]') IP2=$(echo "$2" | tr -d '[:space:]') VALID_IPS=() NFT_TYPES=() SUCCESS_LIST="" FAILED_LIST="" # --- IP 校验函数 --- check_ip() { local input=$1 [[ -z "$input" ]] && return 1 local raw_ip="${input%/*}" local mask="${input#*/}" # 自动识别默认掩码 if [[ "$input" != */* ]]; then if [[ "$raw_ip" =~ : ]]; then mask=128; else mask=32; fi fi # 1. IPv4 校验 # 原来的 2[0-4][0-5] 改为了 2[0-4][0-9] if [[ "$raw_ip" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]; then [[ "$mask" -lt 1 || "$mask" -gt 32 ]] && return 1 echo "ip|$raw_ip/$mask" return 0 fi # 2. IPv6 校验 (简化版正则,兼容性更好) if [[ "$raw_ip" =~ ^(([0-9a-fA-F]{1,4}:){1,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|:(:[0-9a-fA-F]{1,4}){1,7}|::|([0-9a-fA-F]{1,4}:){1,7}:[0-9a-fA-F]{1,4})$ ]]; then [[ "$mask" -lt 1 || "$mask" -gt 128 ]] && return 1 echo "ip6|$raw_ip/$mask" return 0 fi return 1 } process_arg() { local arg=$1 [ -z "$arg" ] && return local res res=$(check_ip "$arg") if [ $? -eq 0 ]; then local full_ip="${res#*|}" VALID_IPS+=("$full_ip") NFT_TYPES+=("${res%|*}") SUCCESS_LIST+="$full_ip " else FAILED_LIST+="$arg " fi } process_arg "$IP1" process_arg "$IP2" # --- 极简反馈逻辑 --- if [ ${#VALID_IPS[@]} -eq 0 ]; then echo "Error: No valid IP provided ($FAILED_LIST)" exit 1 fi # 执行 Nftables 操作 nft flush chain $FAMILY $TABLE_NAME $CHAIN_NAME || { echo "Error: NFT chain not found"; exit 1; } for i in "${!VALID_IPS[@]}"; do nft add rule $FAMILY $TABLE_NAME $CHAIN_NAME ${NFT_TYPES[$i]} saddr ${VALID_IPS[$i]} accept done # 成功返回 echo "OK: Allowed $SUCCESS_LIST" EOF </syntaxhighlight>解释一下代码框里面指令的意思 * '''<code>cat</code> (Concatenate)''':原本是用来“查看”或“拼接”内容的,但在这种组合中,它负责接收你输入的一大段文字。 * '''<code><<</code> (输入重定向)''':这叫“在此处开始读取”。它告诉系统:“别去翻别的文件了,接下来的内容就是我要给你的,直到我遇到结束标记为止。” * '''<code>'EOF'</code> (End Of File)''': ** '''开始标志''':它是你自定义的一个“暗号”。 ** '''为什么要加单引号 <code>' '</code>?''': 加了单引号,系统就会“原样搬运”中间的内容,不会去解析里面的 <code>$变量</code>。这对于写入包含变量的脚本至关重要,否则这些变量在写入文件前就会被当前系统搞乱。 * '''<code>></code> (覆盖写入)''':它的意思是“清空目标文件并把内容倒进去”。 * '''<code>/root/update_fw.sh</code>''':这是目的地。系统会在指定路径创建或覆盖这个脚本文件。 * 中间的内容 就是要写入文件的内容 是我们的核心代码 * '''最后的 <code>EOF</code>''':这是“结束暗号”。系统看到它,就知道“打包”结束了,正式保存文件。 [[File:Apinftedit1.png|border]] 我们可以看到最后蓝色框的时候 有点混乱 没事的 直接按回车就行了 然后我们可以输入 <code>cat /root/update_fw.sh</code> 查看一下文件内容 确认有写入内容就好了 [[File:Catupdateip.png|border]] 创建好后 [[File:Apinftquanxian.png|border]] 你可以先输入 <code>ls -l /root/update_fw.sh</code> 这个意思是 以长格式 查看/root/update_fw.sh 文件的信息 * 第一位 - 代表是文件的意思 d是目录 * 第二位到第四位 rw- 就是 拥有这个文件的人的权限 第一个代表的是读取 如果有这个权限显示r如果没有就是-第二个是写入(编辑)的权限有这个权限就显示w没有就是-第三位是执行(运行)这个文件的权限有就显示x没有就显示- 这里显示-证明在chmod之前是没有执行权限的 * <code>r--</code> 这个文件所属组 的权限 同上 第一位是读取r说明有 第二位是-说明没有写入权限 第三位是-说明没有执行权限 * <code>r--</code> 这个是其他人 也是一样的 有读取权限 没有写入和执行权限 * 1 代表这个文件在磁盘上只有这一个‘ * root root 第一个root 代表拥有这个文件的人 第二个 root 代表这个文件属于root组 * 2675 文件大小Byte * Jan 22 01:07 修改时间 * /root/update_fw.sh 文件信息的文件 为了安全取消掉其他的权限我们输入 <code>chmod 700 /root/update_fw.sh</code> 这个指令的意思是 设置这个文件的权限是700 700的意思就是只有这个文件的拥有人(root ls -l看到的)才可以读取写入和执行 其他的两个0代表 所属组没有任何权限和 其他所有人没有任何权限。 这样,只有 root 用户能看到这个脚本的内容,也只有 root 能运行它。 === 调用API部分 === 获取 搬瓦工服务器的API_Key和veid 请参考 [[搬瓦工api使用]] == 使用搬瓦工API触发服务器上的脚本变更防火墙nftables的chain 从而实现动态更新白名单ip == === ipv6的网段 V6_MASK === 这个..如果你想同时更新ipv6的白名单 有一个问题 就是ipv6 每个设备都有一个ipv6地址(各不相同) ipv4的时候你用电脑手机连接到同一个路由器的话一般都是走的同一个ipv4地址 而ipv6不同…所以如果你只是更新了你这个设备的ipv6地址的话…别的设备仍然不在白名单中…这就需要网段 ==== 请登录路由器 ==== [[File:Router1.png|border]] 找到这个前缀长度…把V6_MASK改成60就行了这样就是说 连接路由器的 都可以进白名单了 所有的代码中都有一个可以修改的变量.. V6_MASK="/64" 单个设备请改为 /128 一些地区可能是48 但48有点危险范围太大 你的邻居可能也在这之中 那为什么是64呢 因为我的是64……哦 我记错了 我是60…. == 可实时更新ip变化的办法 == === Linux系 === ==== OpenWrt类 ==== ===== 检查是否安装了curl ===== 输入 <code>curl</code> 如果显示 -ash: curl not found 安装curl和证书 为了访问https网站 <code>opkg update && opkg install curl ca-bundle</code> [[File:Openwrtcurl.png|border]] curl 8.12.1有这样的版本号 有IPv6 有ssl 确保有他们就可以啦 ===== 检查 获取ip 的url是否有效 ===== 在使用前先在ssh里面输入 <code>curl -s --max-time 5 <nowiki>https://ifconfig.me</nowiki></code> 进行测试 [[File:Curltestgetmyip.png|border]] 看看能不能获取ip地址 红色方块里面的就是ip地址 如果不能…. 在后续的代码块中修改这两个=后面的内容 CHECK_URL_V4="<nowiki>https://ifconfig.me</nowiki>" 改成 CHECK_URL_V4=”<nowiki>https://ident.me”</nowiki> CHECK_URL_V6="<nowiki>https://ifconfig.me</nowiki>" 改成 CHECK_URL_V6=” <nowiki>http://v6.ipip.net”</nowiki> ==== 开始 ==== 在 OpenWrt 中,每当接口(WAN)状态发生变化(比如重连、获取到新 IP、掉线)时,系统会自动触发对应的脚本。 OpenWrt 的网络热插拔脚本存放在: <code>/etc/hotplug.d/iface/</code> '''进入目录:'''<code>cd /etc/hotplug.d/iface/</code> [[File:Openwrtcd.png|border]] '''创建脚本:''' 修改下面代码 你可以先复制到记事本或者别的文本编辑工具里面 最前面的 export VEID="你的VEID" export API_KEY="你的API_KEY" 改成类似这样的格式 export VEID="10202" export API_KEY="private_xxxxx" 请根据你实际的veid和API_Key修改 这两个如果你知道干嘛的也可以改 CACHE_FILE="/etc/config/vps_last_ip" 保存上传的ip防止重复调用API LOG_FILE="/tmp/vps_sync_error.log" 把执行过程和结果保存到这个文件里 最后要检查的 输入 <code>ls /etc/hotplug.d/iface/99-sync-vps-firewall</code> 检查一下 有没有同名的其他脚本 下图就是没有 就不需要修改 [[File:Testfileis.png|border]] 下图就是有 那么你就要换一个名字 /etc/hotplug.d/iface/99-这里改成你想要的名字 比如 /etc/hotplug.d/iface/99-sync-vps-firewall1 [[File:Testfileno.png|border]] 修改后…复制粘贴到ssh里面 回车就创建好脚本了 代码块如下:<syntaxhighlight lang="bash"> cat << 'EOF' > /etc/hotplug.d/iface/99-sync-vps-firewall #!/bin/sh # 只要是接口启动(ifup)就触发 [ "$ACTION" = "ifup" ] || exit 0 # --- 用户配置区 --- export VEID="你的VEID" export API_KEY="你的API_KEY" # 用户可以分别设置获取地址(可以相同,也可以不同) CHECK_URL_V4="https://ifconfig.me" CHECK_URL_V6="https://ifconfig.me" V6_MASK="/64" # IPv6 掩码 CACHE_FILE="/etc/config/vps_last_ip" LOG_FILE="/tmp/vps_sync.log" MAX_LINES=100 # --- 文件初始化与清理函数 --- init_files() { sleep 10 # 1. 处理日志文件 if [ ! -f "$LOG_FILE" ]; then touch "$LOG_FILE" chmod 644 "$LOG_FILE" echo "$(date): [系统] 初始日志文件已创建" >> "$LOG_FILE" else # 日志滚动清理逻辑 local current_lines=$(wc -l < "$LOG_FILE") if [ "$current_lines" -gt "$MAX_LINES" ]; then echo "$(tail -n 50 "$LOG_FILE")" > "$LOG_FILE" echo "$(date): [系统] 日志滚动清理完成" >> "$LOG_FILE" fi fi # 2. 处理缓存文件及其目录 local cache_dir=$(dirname "$CACHE_FILE") if [ ! -d "$cache_dir" ]; then mkdir -p "$cache_dir" echo "$(date): [系统] 创建缓存目录: $cache_dir" >> "$LOG_FILE" fi if [ ! -f "$CACHE_FILE" ]; then touch "$CACHE_FILE" # 初始化空变量,防止脚本第一次读取时报错 echo "LAST_IP4=\"\"" > "$CACHE_FILE" echo "LAST_IP6=\"\"" >> "$CACHE_FILE" echo "$(date): [系统] 初始缓存文件已创建" >> "$LOG_FILE" fi } # --- IPv4 暴力获取函数 --- get_v4() { local count=0 while [ $count -lt 10 ]; do local res=$(curl -s --max-time 5 "$CHECK_URL_V4" 2>/dev/null) if echo "$res" | grep -Eq "^([0-9]{1,3}\.){3}[0-9]{1,3}$"; then echo "$res" && return 0 fi count=$((count + 1)) sleep 2 done return 1 } # --- IPv6 暴力获取函数 --- get_v6() { local count=0 while [ $count -lt 10 ]; do local res=$(curl -s --max-time 5 "$CHECK_URL_V6" 2>/dev/null) if echo "$res" | grep -q ":"; then echo "${res}${V6_MASK}" return 0 fi count=$((count + 1)) sleep 1 done ip6=$(ip -6 addr show scope global | grep inet6 | awk '{print $2}' | cut -d/ -f1 | grep -E '^(2|3)' | head -n 1) if [ -n "$ip6" ]; then echo "${ip6}${V6_MASK}" return 0 fi return 1 } # 1. 初始化 init_files # 2. 执行双栈并行/独立获取 CURRENT_IP4=$(get_v4) CURRENT_IP6=$(get_v6) # 3. 基础校验:至少得有一个 IP 吧 if [ -z "$CURRENT_IP4" ] && [ -z "$CURRENT_IP6" ]; then echo "$(date): [错误] 尝试10次后仍无法获取到任何有效IP" >> "$LOG_FILE" exit 1 fi # 4. 缓存对比 (防重复刷 API) [ -f "$CACHE_FILE" ] && . "$CACHE_FILE" if [ "$CURRENT_IP4" = "$LAST_IP4" ] && [ "$CURRENT_IP6" = "$LAST_IP6" ]; then exit 0 fi # 5. 调用 API CMD="bash /root/update_fw.sh $CURRENT_IP4 $CURRENT_IP6" RESPONSE_FULL=$(curl -s -w "%{http_code}" -X POST \ --data "veid=${VEID}&api_key=${API_KEY}" \ --data-urlencode "command=${CMD}" \ "https://api.64clouds.com/v1/basicShell/exec") # 6. 解析结果 HTTP_CODE="${RESPONSE_FULL:${#RESPONSE_FULL}-3}" RESPONSE_JSON="${RESPONSE_FULL:0:${#RESPONSE_FULL}-3}" RESPONSE_CLEAN=$(echo "$RESPONSE_JSON" | tr -d '\n\r ') ERROR_CODE=$(echo "$RESPONSE_CLEAN" | grep -o '"error":[0-9]*' | cut -d: -f2) MESSAGE=$(echo "$RESPONSE_CLEAN" | grep -o '"message":"[^"]*"' | sed 's/"message":"//;s/"$//') # 7. 写入中文日志 if [ "$HTTP_CODE" = "200" ] && [ "$ERROR_CODE" = "0" ]; then echo "LAST_IP4=\"$CURRENT_IP4\"" > "$CACHE_FILE" echo "LAST_IP6=\"$CURRENT_IP6\"" >> "$CACHE_FILE" echo "$(date): [成功] IP变更同步成功。IPv4: $CURRENT_IP4, IPv6: $CURRENT_IP6. VPS反馈: $MESSAGE" >> "$LOG_FILE" echo "同步成功: $MESSAGE" else [ -z "$MESSAGE" ] && MESSAGE="请求异常: $RESPONSE_JSON" echo "$(date): [失败] 同步失败。详细原因: $MESSAGE" >> "$LOG_FILE" echo "同步失败: $MESSAGE" fi EOF </syntaxhighlight>[[File:Catcmd1.png|border]]就像这样粘贴后回车就行 输入<code>chmod 755 /etc/hotplug.d/iface/99-sync-vps-firewall</code>赋予执行权限 输入 <code>ls -l /etc/hotplug.d/iface/99-sync-vps-firewall</code> 查看赋予权限是否成功 [[File:Openwrtisok.png|border]]这样你可以重启 试试看… 可以输入 <code>cat /tmp/vps_sync_error.log</code> 查看是否成功 [[File:Openwrtlastok.png|border]] 前面的蓝色框框说成功指的是API成功了 里面的ip是本地上传给服务器更新的ip 后面红色框框 OK才是防火墙成功的意思 后面的ip就是更新的ip 如果有一个ip无效或者…就不会显示了 ==== 常见错误 [[File:Openwrterror.png|border]] ==== 身份验证失败 意思就是说 veid 或者 api_key 的内容错误 [[File:Openwrterror1.png|border]] 没有找到链 你可以看到 蓝色框的是防火墙指令..红色框是表 可能是 表(inet my_firewall) 或者 链(allowed_ip) 的名字和服务器防火墙的对不上 你可以去服务器<code>nft list ruleset</code>看一下 ==== 华硕路由器 官方固件 ==== 因为官方固件没有提供 重新连接网络 后执行脚本的功能 所以我们需要一台本地的Linux服务器了(不是防火墙所在的那个服务器哦)… ===== 查看Linux服务器的ip (本地的局域网内的) ===== ssh连接的那个ip就是了… 如果你忘记了 输入 <code>ip addr</code> 找个eth0或者 ens18 这样 一般都是默认网络接口 里面的ip地址 蓝色框框 [[File:Seeserverip.png|border]] ===== 借助监听远程日志触发API更新防火墙白名单IP ===== 用浏览器登陆你的路由器后台 输入用户名和密码 一般的地址是 192.168.1.1 如果不是可以打开 <nowiki>http://www.asusrouter.com/</nowiki> 试试 [[File:Loginrouter.png|border]] 找到系统记录 单击 [[File:Syslog.png|border]] [[File:Logre.png|border]] 远程记录服务器 输入 你的 本地局域网linux服务器的ip 远程记录服务器端口 默认514 '''如果你的linux服务器占用'''514的话 就改一下 ====== 如何查看是否占用 ====== ssh连接那台服务器 '''切换root账户''' * 输入命令:<code>su -</code>''(注意:su 后面有个空格和减号,这很重要,代表同时切换环境变量)'' * 输入 Root 密码(输入时看不见)。 * 此时你的提示符会变成 <code>#</code>,代表你又是 Root 了。 [[File:Su-.png|border]] 输入 <code>sudo ss -tunlp | grep :514</code> 如果你没有安装sudo就会提示 [[File:Errorsudo.png|border]] 那就不需要输入sudo 了 直接 <code>ss -tunlp | grep :514</code> [[File:Ss.png|border]] 这样有输出 就是被占用了 占用的话换一个就行了 这样没有输出 就是没占用 [[File:Noss.png|border]] 然后点击 应用本页面设置 ===== 另外一台Linux服务器部分 不是防火墙所在的那个服务器哦 ===== ssh连接后 ====== '''切换到root账户''' ====== * 输入命令:<code>su -</code>''(注意:su 后面有个空格和减号,这很重要,代表同时切换环境变量)'' * 输入 Root 密码(输入时看不见)。 * 此时你的提示符会变成 <code>#</code>,代表你又是 Root 了。 [[File:Su-.png|border]] ====== 安装socat ====== socat的功能很强大 是一个多功能的网络工具 我们这里用于接收路由器发过来的日志… '''Debian / Ubuntu / PVE / Armbian 系:''' <code>apt update && apt install socat -y</code> '''Red Hat / CentOS / Rocky Linux 系:''' <code>yum install socat -y</code> 新一些Red Hat/CentOS/Rocky Linux希的系统可以使用<code>dnf install socat -y</code> 安装后 输入 <code>socat -V</code> 确认安装成功 [[File:Socatok.png|border]] ====== 检查 获取ip 的url是否有效 ====== 在使用前先在ssh里面输入 <code>curl -s --max-time 5 <nowiki>https://ifconfig.me</nowiki></code> 进行测试 [[File:Curltestgetmyip.png|border]] 看看能不能获取ip地址 红色方块里面的就是ip地址 如果不能…. 在代码块中修改这两个=后面的内容 CHECK_URL_V4="<nowiki>https://ifconfig.me</nowiki>" 改成 CHECK_URL_V4=”<nowiki>https://ident.me”</nowiki> CHECK_URL_V6="<nowiki>https://ifconfig.me</nowiki>" 改成 CHECK_URL_V6=” <nowiki>http://v6.ipip.net”</nowiki> ====== 创建脚本 ====== 修改下面代码块 的代码 你可以复制到记事本或者其他文本编辑器里面 修改 最前面的 export VEID="你的VEID" export API_KEY="你的API_KEY" 改成类似这样的格式 export VEID="10202" export API_KEY="private_xxxxx" 请根据你实际的veid和API_Key修改 这两个如果你知道干嘛的也可以改 CACHE_FILE="/etc/config/vps_last_ip" 保存上传的ip防止重复调用API LOG_FILE="/tmp/vps_sync_error.log" 把执行过程和结果保存到这个文件里 根据刚才测试的结果来决定要不要替换 CHECK_URL_V4="<nowiki>https://ifconfig.me</nowiki>" CHECK_URL_V6="<nowiki>https://ifconfig.me</nowiki>" V6_MASK="/64" 也可以修改 详情看上方的 '''ipv6的网段 V6_MASK''' 最后要检查的 输入 <code>ls /root/checkip.sh</code> 检查一下 有没有同名的其他脚本 下图就是没有 就不需要修改 [[File:Nocheckip.png|border]] 下图这样就是有 就需要修改/root/checkip.sh 比如修改成 /root/checkip1.sh [[File:Havecheckip.png|border]] 修改后 全部选择 复制粘贴 到ssh里面 按回车 代码块:<syntaxhighlight lang="bash"> cat << 'EOF' > /root/checkip.sh #!/bin/bash # --- 用户配置区 --- export VEID="你的VEID" export API_KEY="你的API_KEY" # 获取 IP 的地址 CHECK_URL_V4="https://ifconfig.me" CHECK_URL_V6="https://ifconfig.me" V6_MASK="/64" # IPv6 掩码 CACHE_FILE="/etc/config/vps_last_ip" LOG_FILE="/var/log/vps_sync.log" MAX_LINES=100 # 日志保留行数 # --- 1. 初始化文件与目录 --- init_files() { # 处理日志文件 if [ ! -f "$LOG_FILE" ]; then touch "$LOG_FILE" chmod 644 "$LOG_FILE" else # 日志滚动清理 local current_lines=$(wc -l < "$LOG_FILE") if [ "$current_lines" -gt "$MAX_LINES" ]; then echo "$(tail -n 100 "$LOG_FILE")" > "$LOG_FILE" echo "$(date): [系统] 日志滚动清理完成 (保留末尾100行)" >> "$LOG_FILE" fi fi # 处理缓存目录及文件 local cache_dir=$(dirname "$CACHE_FILE") [ ! -d "$cache_dir" ] && mkdir -p "$cache_dir" if [ ! -f "$CACHE_FILE" ]; then echo "LAST_IP4=\"\"" > "$CACHE_FILE" echo "LAST_IP6=\"\"" >> "$CACHE_FILE" fi } # --- 2. IPv4 暴力获取函数 --- get_v4() { local count=0 while [ $count -lt 10 ]; do local res=$(curl -s4 --max-time 5 "$CHECK_URL_V4" 2>/dev/null) if echo "$res" | grep -Eq "^([0-9]{1,3}\.){3}[0-9]{1,3}$"; then echo "$res" && return 0 fi count=$((count + 1)) sleep 2 done return 1 } # --- 3. IPv6 暴力获取函数 --- get_v6() { local count=0 while [ $count -lt 10 ]; do local res=$(curl -s6 --max-time 5 "$CHECK_URL_V6" 2>/dev/null) if echo "$res" | grep -q ":"; then echo "${res}${V6_MASK}" return 0 fi count=$((count + 1)) sleep 4 done ip6=$(ip -6 addr show scope global | grep inet6 | awk '{print $2}' | cut -d/ -f1 | grep -E '^(2|3)' | head -n 1) if [ -n "$ip6" ]; then echo "${ip6}${V6_MASK}" return 0 fi return 1 } # --- 4. 核心同步逻辑 --- sync_ip() { # 刚收到日志时,给网络层 5-10 秒的初始化时间 sleep 10 # 获取当前 IP CURRENT_IP4=$(get_v4) CURRENT_IP6=$(get_v6) # 基础校验 if [ -z "$CURRENT_IP4" ] && [ -z "$CURRENT_IP6" ]; then echo "$(date): [错误] 尝试10次后仍无法获取到任何有效IP" >> "$LOG_FILE" return 1 fi # 读取缓存并对比 . "$CACHE_FILE" if [ "$CURRENT_IP4" = "$LAST_IP4" ] && [ "$CURRENT_IP6" = "$LAST_IP6" ]; then echo "$(date): [跳过] IP 未发生变化,取消同步" >> "$LOG_FILE" return 0 fi # 调用 API CMD="bash /root/update_fw.sh $CURRENT_IP4 $CURRENT_IP6" local RESPONSE_FULL=$(curl -s -w "%{http_code}" -X POST \ --data "veid=${VEID}&api_key=${API_KEY}" \ --data-urlencode "command=${CMD}" \ "https://api.64clouds.com/v1/basicShell/exec") # 解析结果 local HTTP_CODE="${RESPONSE_FULL:${#RESPONSE_FULL}-3}" local RESPONSE_JSON="${RESPONSE_FULL:0:${#RESPONSE_FULL}-3}" # 核心解析:压缩 JSON 并提取字段 local CLEAN_JSON=$(echo "$RESPONSE_JSON" | tr -d '\n\r' | tr -s ' ') local ERROR_CODE=$(echo "$CLEAN_JSON" | sed -n 's/.*"error":[ ]*\([0-9]*\).*/\1/p') local MESSAGE=$(echo "$CLEAN_JSON" | sed -n 's/.*"message":[ ]*"\(.*\)"[ ]*}.*/\1/p' | sed 's/\\//g') # 写入日志 if [ "$HTTP_CODE" = "200" ] && [ "$ERROR_CODE" = "0" ]; then echo "LAST_IP4=\"$CURRENT_IP4\"" > "$CACHE_FILE" echo "LAST_IP6=\"$CURRENT_IP6\"" >> "$CACHE_FILE" echo "$(date): [成功] 同步成功。IPv4: $CURRENT_IP4, IPv6: $CURRENT_IP6. VPS反馈: $MESSAGE" >> "$LOG_FILE" else [ -z "$MESSAGE" ] && MESSAGE="$CLEAN_JSON" echo "$(date): [失败] 同步失败。HTTP: $HTTP_CODE, ERROR: $ERROR_CODE, 原因: $MESSAGE" >> "$LOG_FILE" fi } # --- 5. 监听入口 --- init_files # 如果直接运行脚本(无管道输入),执行一次同步 if [ -t 0 ]; then sync_ip else # 如果有管道输入(来自 socat),则监听日志触发 while IFS= read -r line; do if echo "$line" | grep -qi 'local *IP address'; then echo "$(date): [触发] 检测到路由器拨号日志" >> "$LOG_FILE" sync_ip fi done fi EOF </syntaxhighlight>[[File:Cathuashuo.png|border]] 粘贴之后有点混乱 不用管 直接回车就行了 然后 检查一下 输入 <code>cat /root/checkip.sh</code> 有内容就好了 [[File:Catcheckip.png|border]] 授予运行权限 <code>chmod +x /root/checkip.sh</code> 然后输入 <code>ls -l /root/checkip.sh</code> 查看多了三个x 就对了 如果像红色框框没有x 就不对 请重试 <code>chmod +x /root/checkip.sh</code> [[File:Lslcheckip.png|border]] 然后你就可以输入 <code>/root/checkip.sh</code> 如果第一次测试成功了 以后想测试的话运行这个 <code>rm /etc/config/vps_last_ip && /root/checkip.sh</code> 需要<code>rm /etc/config/vps_last_ip</code>删除本地保留的ip记录 就是说如果这个ip记录和获取到的一样是不会运行api执行脚本的 测试一下 相当于是手动更新..不是自动更新 [[File:Testcheckip.png|border]] 不会有内容输出 需要查看日志 <code>cat /var/log/vps_sync.log</code> 如果是下图那样就是成功了 要看红色的 红色框是vps服务器返回的OK 就是真的成功了 Allowed:后面是成功添加的ip 一个是ipv4 一个是ipv6的 蓝色框的成功说的是API使用成功 提交的IP是哪些 在此再次提醒您 使用时 保管好Veid和API_Key 你 看我打码服务器名字 然而还是在这里漏了...以前的打码就没意义了 [[File:Checkipok.png|border]] ====== 常见错误 ====== [[File:Errorapi.png|border]] 身份验证错误 一般代表 api_key 或 veid 的内容填写错误 就是= 后面的 "" 里面的内容 比如VEID="就这里错了" API_KEY="这里" ====== 配置开机启动 和 自动更新 ====== 使用systemctl配置开机启动和 自动根据日志更新 修改以下代码中的 UDP-RECV:514 把514换成你的路由器那里设置的 远程记录服务器端口 比如 515 就改成 UDP-RECV:515 [[File:Logre.png|border]] <code>ExecStart=/bin/sh -c "/usr/bin/socat -u UDP-RECV:514 STDOUT | /root/checkip.sh"</code> 这里面的 <code>/root/checkip.sh</code> 如果你的文件名改了的话 就需要修改… 没改就不用改.. 同理 <code>/etc/systemd/system/router-log-watcher.service</code> 这个地方你也应该输入 <code>ls /etc/systemd/system/router-log-watcher.service</code> 查看文件是否存在.如果存在就改名字 如果不存在就不用改了 和上面服务器部分的 ls /root/update_fw.sh 一样 修改好 全部选择 复制粘贴到ssh里面 然后按回车<syntaxhighlight lang="bash">cat << 'EOF' > /etc/systemd/system/router-log-watcher.service [Unit] Description=Router Log Watcher After=network.target [Service] Type=simple # 管道命令:socat 接收 UDP 514,然后传给脚本 ExecStart=/bin/bash -c "/usr/bin/socat -u UDP-RECV:514 STDOUT | /root/checkip.sh" Restart=always RestartSec=5 # 如果脚本需要 root 权限,确保 User=root User=root [Install] WantedBy=multi-user.target EOF</syntaxhighlight>这个不怎么混乱 直接回车就行 然后 <code>cat /etc/systemd/system/router-log-watcher.service</code> 如果你的文件名字 如果不是这个的话请修改 [[File:Catsystemctl.png|border]] 输入这个 意思是识别新服务 <code>systemctl daemon-reload</code> 在输入这个 意思是 启动并设置开机自启 <code>systemctl enable --now router-log-watcher.service</code> [[File:Startsystemctl.png|border]] 最后输入 <code>systemctl status router-log-watcher.service</code> [[File:Staratok.png|border]] 蓝色的框 是 已经运行了 绿色的是enabled 是 设置了 开机自动启动 现在可以重启路由器获取新的ip试试了 输入 <code>cat /var/log/vps_sync.log</code> 这样就是成功了 [[File:Apinftisok.png|border]] 如果ipv6获取的速度慢 可能出现防火墙没有允许ipv6的情况 [[File:Apinftiserror.png|border]] 遇到极端情况下 可以手动更新 <code>rm -f /etc/config/vps_last_ip && /root/checkip.sh</code> 删除存储的ip然后执行脚本 ip一直相同的话是不会调用api的 另外如果你修改了/root/checkip.sh 那么还要输入 <code>systemctl restart router-log-watcher.service</code> 重启这个服务才生效 如果成功更新ip了 就可以把允许ssh的端口删掉了就真正变成白名单模式了
返回
使用搬瓦工api操作nftables实现更新白名单ip
。
查看“︁使用搬瓦工api操作nftables实现更新白名单ip”︁的源代码
来自md5.pw