Initial commit: OpenWrt firewall management scripts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-08 18:19:24 +08:00
commit 0359abb7dc
6 changed files with 560 additions and 0 deletions

53
CLAUDE.md Normal file
View File

@@ -0,0 +1,53 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
This is a collection of OpenWrt router management scripts for firewall configuration and network diagnostics. The scripts use nftables (fw4) for firewall management and are designed to restrict access to Taiwan IP addresses only.
**Target Device**: OpenWrt 24.10.4 (r28959-29397011cc) at `192.168.42.10`
## Prerequisites
These scripts require an OpenWrt router with:
- `nft` command (nftables with fw4 firewall)
- `curl` for downloading IP lists and checking network status
- `jq` for JSON parsing (test_connection.sh)
- `nc` (netcat) for port connectivity testing
Install dependencies (from `R` file):
```sh
opkg update
opkg install curl
```
## Scripts
### `update_tw_ip.sh`
Downloads the latest Taiwan IP range list from ipdeny.com and updates the nftables `taiwan_ips` set in the `inet fw4` table.
Usage: Run as root, typically via cron or manually:
```sh
sh /root/42_10/update_tw_ip.sh
```
The script flushes the existing set and repopulates it with fresh IP data from `https://www.ipdeny.com/ipblocks/data/countries/tw.zone`.
### `test_connection.sh`
Diagnostic script to verify firewall rules are working correctly. It:
1. Checks the current IP location via `https://ip.lotimmy.com/json`
2. Tests connectivity to specified ports on `125.229.110.50`
3. Reports whether connections succeed or are blocked
Edit the `TARGET_IP` and `PORTS` variables at the top of the script to match your configuration before running.
## Firewall Configuration
These scripts assume an nftables configuration with:
- Table: `inet fw4`
- Set: `taiwan_ips` (type for storing IP ranges)
The firewall should have rules referencing this set to allow/deny traffic based on Taiwan IP membership.

214
README.md Normal file
View File

@@ -0,0 +1,214 @@
# OpenWrt 管理指令
**目標設備**`192.168.42.10`OpenWrt 24.10.4
**WAN IP**`125.229.110.50`PPPoE
---
## 系統狀態確認
```sh
# 開機時間與負載
uptime
# 記憶體用量
free -m
# 磁碟空間
df -h
# 近期系統紀錄
logread -l 50
# 即時追蹤紀錄
logread -f
```
---
## 套件管理
```sh
# 更新套件列表
opkg update
# 安裝套件
opkg install <package_name>
# 移除套件
opkg remove <package_name>
# 列出已安裝套件
opkg list-installed
# 升級所有套件
opkg list-upgradable | cut -f 1 -d ' ' | xargs -r opkg upgrade
```
---
## 防火牆nftables / fw4
```sh
# 列出所有規則
nft list ruleset
# 列出特定 table
nft list table inet fw4
# 重新載入防火牆設定
fw4 restart
# 備份目前規則
nft list ruleset > /etc/nftables.backup
# 清除特定集合
nft flush set inet fw4 taiwan_ips
# 查看 Taiwan IP 集合(元素數量)
nft list set inet fw4 taiwan_ips | grep -c elements
```
---
## 網路診斷
```sh
# 介面清單與狀態
ip -br addr
# 路由表
ip route show
# 測試對外網路
ping -c 4 8.8.8.8
# DNS 查詢
nslookup google.com
# 查看監聽 Port
netstat -tuln
# 測試指定 Port 是否可到達
nc -zv -w 5 <target_ip> <port>
```
---
## 日誌
```sh
# 查看系統紀錄
logread
# 即時監控
logread -f
# 最近 50 筆
logread -l 50
# 過濾防火牆相關
logread | grep -i firewall
```
---
## 服務管理
```sh
# 啟動 / 停止 / 重啟
/etc/init.d/<service> start
/etc/init.d/<service> stop
/etc/init.d/<service> restart
# 查看狀態
/etc/init.d/<service> status
# 開機自動啟動 / 停用
/etc/init.d/<service> enable
/etc/init.d/<service> disable
```
---
## 設定備份與還原
```sh
# 備份整個系統設定
sysupgrade -b /tmp/backup-$(date +%Y%m%d).tar.gz
# 還原設定
sysupgrade -r /tmp/backup-YYYYMMDD.tar.gz
# 備份防火牆設定
cp /etc/config/firewall /etc/config/firewall.bak
# 編輯設定檔
vi /etc/config/firewall
```
---
## Taiwan IP 集合管理
```sh
# 重新抓取並更新 Taiwan IP 清單
sh /root/42_10/update_tw_ip.sh
# 確認目前集合內容
nft list set inet fw4 taiwan_ips
# 手動補充單一 IP如 VPS 未被涵蓋)
nft add element inet fw4 taiwan_ips { <ip_address> }
```
**資料來源**`https://www.ipdeny.com/ipblocks/data/countries/tw.zone`
建議搭配 cron 定期執行 `update_tw_ip.sh`,例如每月一次:
```sh
# crontab -e
0 3 1 * * sh /root/42_10/update_tw_ip.sh
```
---
## 防火牆規則驗證
```sh
# 本機執行SSH 進路由器並格式化輸出規則
sh /root/42_10/show_nft_rules.sh
# 驗證台灣 IP 通行、非台灣 IP 攔截
sh /root/42_10/test_connection.sh
```
`test_connection.sh` 會:
1. 查詢目前出口 IP 所在地(透過 `https://ip.lotimmy.com/json`
2.`125.229.110.50` 的指定 Port`51433`, `31433`)發起測試
3. 判斷結果是否符合預期(台灣 IP 應通過,非台灣 IP 應被攔截)
---
## 轉發規則調整
若需移除已失效的 Port 轉發(如原本指向不存在主機),執行:
```sh
sh /root/42_10/remove_mysql_forward.sh
```
手動移除流程:
```sh
# 找出目標規則
ssh root@192.168.42.10 "uci show firewall | grep <port>"
# 刪除並提交
ssh root@192.168.42.10 "uci delete firewall.<rule_id> && uci commit firewall"
# 重載防火牆
ssh root@192.168.42.10 "fw4 restart"
# 確認規則已移除
ssh root@192.168.42.10 "nft list chain inet fw4 dstnat_wan | grep <port>"
```

99
remove_mysql_forward.sh Executable file
View File

@@ -0,0 +1,99 @@
#!/bin/bash
# 刪除 MySQL 轉發規則 (192.168.42.123 已不存在)
ROUTER_IP="192.168.42.10"
ROUTER_USER="root"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🗑️ 刪除 MySQL 轉發規則工具"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "目標規則:"
echo " - TCP 13306 → 192.168.42.123:3306"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# 方式一:使用 UCI 刪除設定(推薦)
echo "方式一:使用 UCI 指令刪除設定"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "執行以下指令:"
echo ""
echo " # 找出 MySQL forwarding 規則的索引"
echo " ssh ${ROUTER_USER}@${ROUTER_IP} \"uci show firewall | grep 13306\""
echo ""
echo " # 刪除該規則 (假設是 @forwarding[12])"
echo " ssh ${ROUTER_USER}@${ROUTER_IP} \"uci delete firewall.\$(uci show firewall | grep -B1 '13306' | head -1 | sed 's/firewall\.//;s/=.*//')\""
echo ""
echo " # 或直接刪除包含 13306 的規則"
ssh ${ROUTER_USER}@${ROUTER_IP} "
idx=\$(uci show firewall | grep 13306 | head -1 | sed 's/firewall\.//;s/=.*//')
if [ -n \"\$idx\" ]; then
echo \"找到規則: \$idx\"
uci delete firewall.\$idx
uci commit firewall
echo \"✓ 已刪除並提交設定\"
else
echo \"⚠ 找不到包含 13306 的規則\"
fi
"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "方式二:直接編輯設定檔"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "手動編輯 /etc/config/firewall"
echo ""
echo " ssh ${ROUTER_USER}@${ROUTER_IP}"
echo " vi /etc/config/firewall"
echo ""
echo "找到並刪除類似以下的 config forwarding 區塊:"
echo ""
echo " config redirect"
echo " option name 'MySQL_Forward'"
echo " option src 'wan'"
echo " option src_dport '13306'"
echo " option dest 'lan'"
echo " option dest_ip '192.168.42.123'"
echo " option dest_port '3306'"
echo ""
echo "以及 reflection 規則:"
echo ""
echo " config redirect"
echo " option name 'MySQL_Forward (reflection)'"
echo " option src 'lan'"
echo " option src_dport '13306'"
echo " option src_ip '192.168.42.0/24'"
echo " option src_dip '125.229.110.50'"
echo " option dest 'lan'"
echo " option dest_ip '192.168.42.123'"
echo " option dest_port '3306'"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "重載防火牆"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "修改完成後執行:"
echo ""
echo " ssh ${ROUTER_USER}@${ROUTER_IP} \"fw4 restart\""
echo ""
echo "或:"
echo ""
echo " ssh ${ROUTER_USER}@${ROUTER_IP} \"/etc/init.d/firewall restart\""
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "驗證規則已刪除"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "執行:"
echo ""
echo " ssh ${ROUTER_USER}@${ROUTER_IP} \"nft list chain inet fw4 dstnat_wan | grep 13306\""
echo ""
echo "如果沒有輸出,表示規則已成功刪除。"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

146
show_nft_rules.sh Executable file
View File

@@ -0,0 +1,146 @@
#!/bin/bash
# OpenWrt 防火牆規則查看腳本
# 用途SSH 連線到防火牆並格式化顯示 nftables 規則
ROUTER_IP="192.168.42.10"
ROUTER_USER="root" # 如果使用其他帳號請修改
# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
GRAY='\033[0;90m'
NC='\033[0m' # No Color
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE}🔒 OpenWrt 防火牆規則檢視工具${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GRAY}目標設備: ${ROUTER_IP}${NC}"
echo -e "${GRAY}指令: nft list ruleset${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
# 取得規則並暫存到 /tmp
TEMP_FILE=$(mktemp)
ssh ${ROUTER_USER}@${ROUTER_IP} "nft list ruleset" > "$TEMP_FILE" 2>&1
# 檢查 SSH 是否成功
if [ $? -ne 0 ]; then
echo -e "${RED}❌ SSH 連線失敗!${NC}"
echo -e "${YELLOW}請確認:${NC}"
echo -e " 1. 防火牆設備是否開機 (${ROUTER_IP})"
echo -e " 2. SSH 服務是否啟用"
echo -e " 3. 網路連線是否正常"
echo -e " 4. SSH 金鑰或密碼設定"
rm -f "$TEMP_FILE"
exit 1
fi
# 解析並顯示規則
current_section=""
in_table=false
in_chain=false
in_set=false
in_rule=false
while IFS= read -r line; do
# 跳過空行(但保留段落分隔)
if [[ -z "$line" ]]; then
echo ""
continue
fi
# Table 定義
if [[ "$line" =~ ^table[[:space:]] ]]; then
echo -e "\n${GREEN}╭─────────────────────────────────────────────────────────${NC}"
echo -e "${GREEN}${line}${NC}"
echo -e "${GREEN}╰─────────────────────────────────────────────────────────${NC}"
in_table=true
continue
fi
# Chain 定義
if [[ "$line" =~ ^[[:space:]]*chain[[:space:]] ]]; then
chain_name=$(echo "$line" | sed -E 's/.*chain[[:space:]]+(\w+).*/\1/')
echo -e "\n${YELLOW} ▶ Chain: ${CYAN}${chain_name}${NC}"
in_chain=true
continue
fi
# Set 定義
if [[ "$line" =~ ^[[:space:]]*set[[:space:]] ]]; then
set_name=$(echo "$line" | sed -E 's/.*set[[:space:]]+(\w+).*/\1/')
echo -e "\n${BLUE} 📦 Set: ${CYAN}${set_name}${NC}"
# 顯示 set 的類型等資訊
set_info=$(echo "$line" | sed -E 's/[[:space:]]*set[[:space:]]+(\{.*)/\1/')
echo -e "${GRAY} ${set_info}${NC}"
in_set=true
continue
fi
# 規則內容
if [[ "$line" =~ ^[[:space:]]*meta[[:space:]] ]] || [[ "$line" =~ ^[[:space:]]*ip[[:space:]] ]] || [[ "$line" =~ ^[[:space:]]*tcp[[:space:]] ]] || [[ "$line" =~ ^[[:space:]]*udp[[:space:]] ]] || [[ "$line" =~ ^[[:space:]]*icmp[[:space:]] ]] || [[ "$line" =~ ^[[:space:]]*ct[[:space:]] ]]; then
# 規則動作著色
if [[ "$line" =~ accept ]]; then
action_color="${GREEN}"
elif [[ "$line" =~ drop|reject ]]; then
action_color="${RED}"
elif [[ "$line" =~ jump ]]; then
action_color="${YELLOW}"
else
action_color="${NC}"
fi
# 著色顯示規則
colored_line="$line"
[[ "$line" =~ accept ]] && colored_line=$(echo "$line" | sed -E "s/accept/${GREEN}accept${NC}/g")
[[ "$line" =~ drop ]] && colored_line=$(echo "$line" | sed -E "s/drop/${RED}drop${NC}/g")
[[ "$line" =~ reject ]] && colored_line=$(echo "$line" | sed -E "s/reject/${RED}reject${NC}/g")
[[ "$line" =~ jump ]] && colored_line=$(echo "$line" | sed -E "s/jump[[:space:]]+(\w+)/jump ${YELLOW}\1${NC}/")
echo -e " ${colored_line}"
continue
fi
# Set 元素 (IP 位址)
if [[ "$line" =~ ^[[:space:]]*[0-9] ]] || [[ "$line" =~ ^[[:space:]]*elements[[:space:]]*= ]]; then
if [[ "$line" =~ elements[[:space:]]*= ]]; then
echo -e " ${GRAY}Elements:${NC}"
else
echo -e " ${line}"
fi
continue
fi
# 其他設定
if [[ "$line" =~ ^[[:space:]]*\}[[:space:]]*$ ]]; then
# 結束符號,不顯示
continue
fi
# policy 等
if [[ "$line" =~ policy ]]; then
policy=$(echo "$line" | sed -E 's/.*policy[[:space:]]+(\w+).*/\1/')
if [[ "$policy" == "accept" ]]; then
echo -e " ${GRAY}policy: ${GREEN}${policy}${NC}"
else
echo -e " ${GRAY}policy: ${RED}${policy}${NC}"
fi
continue
fi
# 其他內容直接顯示
if [[ ! -z "$line" ]]; then
echo -e " ${GRAY}${line}${NC}"
fi
done < "$TEMP_FILE"
rm -f "$TEMP_FILE"
echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${GREEN}✓ 檢視完成${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"

34
test_connection.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
# --- 這裡要改成你真正有開的 Port ---
TARGET_IP="125.229.110.50"
# PORTS=("51433")
PORTS=("51433" "31433")
echo "--- [第一步:身份確認] ---"
MY_INFO=$(curl -s https://ip.lotimmy.com/json)
MY_IP=$(echo $MY_INFO | jq -r '.ip')
MY_REGION=$(echo $MY_INFO | jq -r '.region_name')
MY_ASN=$(echo $MY_INFO | jq -r '.asn_org')
echo "目前位置:$MY_REGION ($MY_ASN)"
echo "對外 IP $MY_IP"
# 判斷是否為台灣 IP
SHOULD_PASS=false
if [[ "$MY_REGION" == *"Taipei"* ]] || [[ "$MY_ASN" == *"Data Communication"* ]]; then
SHOULD_PASS=true
fi
echo -e "\n--- [第二步:連線測試] ---"
for PORT in "${PORTS[@]}"
do
# 測試連線
nc -zv -w 5 $TARGET_IP $PORT > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "[成功] Port $PORT 連線正常。"
else
echo -n "[攔截] Port $PORT 無法連線。"
[ "$SHOULD_PASS" = true ] && echo " (錯誤:你是台灣 IP 卻被擋掉!)" || echo ""
fi
done

14
update_tw_ip.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
# 下載最新台灣 IP 清單
curl -s https://www.ipdeny.com/ipblocks/data/countries/tw.zone > /tmp/tw.zone
# 更新集合 (fw4 會自動處理 auto-merge)
nft flush set inet fw4 taiwan_ips
for ip in $(cat /tmp/tw.zone); do
nft add element inet fw4 taiwan_ips { $ip }
done
# 萬一你的 VPS IP 沒被網段涵蓋,這邊可以手動補強 (選配)
# nft add element inet fw4 taiwan_ips { 211.23.141.206 }
logger "Firewall: Taiwan IP set updated."