购买了 IPLC 中转服务器,用于加速代理速度,可以借助 nftables 来做简单的 NAT 转发
因为 nftables 本身就集成在 Linux 内核中,无需额外安装,且性能优异
无需担心协议被识别的问题,NAT 转发只会修改 IP 和端口,不会改变数据包的内容,加密依旧是加密,只要你的代理协议本身足够隐蔽即可
数据包依旧在本地加密,在落地端解密,中间的 IPLC 机器不会看到任何明文数据(运营商和 IPLC 服务商也看不到)
为了方便添加多个落地加速,撰写一个脚本用于方便添加新的中转服务
编辑 nat-shaper.sh ,其内容如下:
#!/bin/bash
# NAT 转发管理 (纯 nftables 版本 - 修复/加固 + 支持端口限速 + 双向限速)
# - add <PORT> <IP:PORT> [--rate Mbps]
# - 限速=去程(→rip:rport) + 回程(←rip:rport) 各自 limit+drop,TCP/UDP 同步
# - nft 不支持 bit/s;将 Mbps 换算为 kbytes/second(1 Mbps = 125 kB/s)
set -e
NFT="/usr/sbin/nft"
TABLE="natmgr"
CONFIG_FILE="/etc/nftables-natmgr.conf"
need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "缺少命令: $1"; exit 1; }; }
need_cmd "$NFT"
if [[ $EUID -ne 0 ]]; then echo "请使用 root 权限运行。"; exit 1; fi
init_table() {
if ! $NFT list table ip $TABLE >/dev/null 2>&1; then
echo "[+] 创建表 $TABLE 和必要的链"
$NFT add table ip $TABLE
$NFT add chain ip $TABLE prerouting { type nat hook prerouting priority -100\; }
$NFT add chain ip $TABLE postrouting { type nat hook postrouting priority 100\; }
$NFT add chain ip $TABLE forward { type filter hook forward priority 0\; }
fi
}
save_rules() {
echo "#!/usr/sbin/nft -f" > "$CONFIG_FILE"
$NFT list table ip $TABLE >> "$CONFIG_FILE"
echo "[*] 规则已保存到 $CONFIG_FILE"
}
show_rules() {
echo ""
echo "============== 当前 NAT 转发情况 =============="
local rules
rules=$($NFT list chain ip $TABLE forward 2>/dev/null | grep -E 'comment "NAT-[0-9]+-.*"' || true)
if [[ -z "$rules" ]]; then
echo "暂无 NAT 转发规则"
echo "=============================================="
return
fi
local ports
ports=$(echo "$rules" | sed -n 's/.*comment "NAT-\([0-9]*\)-.*/\1/p' | sort -nu)
for port in $ports; do
local any_rule rip rport
any_rule=$(echo "$rules" | grep -E "comment \"NAT-${port}-.*\"" | head -1)
rip=$(echo "$any_rule" | grep -oE 'ip (saddr|daddr) [0-9.]+' | awk '{print $3}')
rport=$(echo "$any_rule" | grep -oE '(dport|sport) [0-9]+' | awk '{print $2}')
[[ -n "$rip" && -n "$rport" ]] && echo "本地端口 ${port} ↔ ${rip}:${rport}"
done
echo "=============================================="
}
del_rule() {
local lport=$1
echo "[*] 删除端口 $lport 相关规则"
local deleted=0
for chain in prerouting postrouting forward; do
local handles
handles=$($NFT -a list chain ip $TABLE "$chain" 2>/dev/null | \
awk -v p="NAT-"$lport"-" '
/comment/ && $0 ~ p {
for(i=1;i<=NF;i++) if($i=="handle"){print $(i+1)}
}' || true)
if [[ -n "$handles" ]]; then
for h in $handles; do
$NFT delete rule ip $TABLE "$chain" handle "$h" 2>/dev/null || true
echo "[-] 删除 $chain 链规则 handle $h"
deleted=$((deleted+1))
done
fi
done
if [[ $deleted -eq 0 ]]; then
echo "[-] 未找到端口 $lport 的相关规则"
else
echo "[*] 共删除 $deleted 条规则"
save_rules
fi
}
to_kbytes_per_sec() { awk -v r="$1" 'BEGIN { printf("%d\n", (r*125)+0.5) }'; }
parse_add_args() {
ADD_LPORT=""; ADD_REMOTE=""; ADD_RATE=""
if [[ $# -lt 2 ]]; then echo "错误:add 需要至少 2 个参数"; show_help; exit 1; fi
ADD_LPORT="$1"; shift
ADD_REMOTE="$1"; shift
while [[ $# -gt 0 ]]; do
case "$1" in
--rate) shift
[[ -z "$1" ]] && { echo "错误:--rate 需要数值(Mbps)"; exit 1; }
[[ ! "$1" =~ ^[0-9]+(\.[0-9]+)?$ ]] && { echo "错误:--rate 仅支持数字(可小数)"; exit 1; }
ADD_RATE="$1"; shift;;
*) echo "未知参数:$1"; exit 1;;
esac
done
}
# 生成一组限速规则(方向由 direction 决定:dst=去程 daddr/dport;src=回程 saddr/sport)
add_limit_rules_pair() {
local direction="$1" proto="$2" ipaddr="$3" port="$4" rate_kbytes="$5" lport="$6"
local tag mid verb1 verb2
if [[ "$direction" == "dst" ]]; then
tag="NAT-${lport}-${proto}-limit" # 去程
if [[ "$proto" == "tcp" ]]; then
verb1="ip daddr $ipaddr tcp dport $port"
else
verb1="ip daddr $ipaddr udp dport $port"
fi
else
tag="NAT-${lport}-${proto}-limit-rev" # 回程
if [[ "$proto" == "tcp" ]]; then
verb1="ip saddr $ipaddr tcp sport $port"
else
verb1="ip saddr $ipaddr udp sport $port"
fi
fi
# burst:TCP=5MB,UDP=2MB
if [[ "$proto" == "tcp" ]]; then mid="burst 5 mbytes"; else mid="burst 2 mbytes"; fi
# limit -> accept;随后 drop 兜底
$NFT add rule ip $TABLE forward $verb1 limit rate ${rate_kbytes} kbytes/second $mid counter accept comment "$tag"
$NFT add rule ip $TABLE forward $verb1 counter drop comment "${tag/-limit/-over}"
}
add_rule() {
local lport="$1" remote="$2" rate="$3"
local rip=${remote%%:*} rport=${remote##*:}
[[ -z "$rip" || -z "$rport" ]] && { echo "目标格式错误,应为 IP:PORT"; exit 1; }
echo "[+] 添加规则: $lport → $rip:$rport"
del_rule "$lport"
# PREROUTING DNAT
$NFT add rule ip $TABLE prerouting tcp dport $lport dnat to $rip:$rport comment "NAT-${lport}-tcp-preroute"
$NFT add rule ip $TABLE prerouting udp dport $lport dnat to $rip:$rport comment "NAT-${lport}-udp-preroute"
# POSTROUTING MASQUERADE
$NFT add rule ip $TABLE postrouting ip daddr $rip masquerade comment "NAT-${lport}-post"
if [[ -n "$rate" ]]; then
local rate_kbytes; rate_kbytes=$(to_kbytes_per_sec "$rate")
[[ "$rate_kbytes" -lt 1 ]] && { echo "错误:--rate 太小(<$rate Mbps)导致 <1 kB/s"; exit 1; }
# 去程(client->server)+ 回程(server->client),TCP/UDP 各两条 => 共 8 条
add_limit_rules_pair dst tcp "$rip" "$rport" "$rate_kbytes" "$lport"
add_limit_rules_pair dst udp "$rip" "$rport" "$rate_kbytes" "$lport"
add_limit_rules_pair src tcp "$rip" "$rport" "$rate_kbytes" "$lport"
add_limit_rules_pair src udp "$rip" "$rport" "$rate_kbytes" "$lport"
echo "[*] 端口 $lport 已启用双向限速 ${rate}Mbps(≈ ${rate_kbytes} kB/s,TCP/UDP)"
else
# 不限速:双协议直接放行(去/回不区分,回程反正还会经过其他链)
$NFT add rule ip $TABLE forward ip daddr $rip tcp dport $rport counter accept comment "NAT-${lport}-tcp"
$NFT add rule ip $TABLE forward ip daddr $rip udp dport $rport counter accept comment "NAT-${lport}-udp"
echo "[*] 端口 $lport 不限速"
fi
save_rules
echo "[+] 规则添加完成"
show_rules
}
cleanup_rules() {
echo "[*] 清理重复规则..."
local ports cleaned=0
ports=$($NFT list chain ip $TABLE forward 2>/dev/null | \
grep -oE 'comment "NAT-[0-9]+-' | sed -n 's/comment "NAT-\([0-9]*\)-/\1/p' | sort -nu || true)
for port in $ports; do
local tcp_count udp_count
tcp_count=$($NFT list chain ip $TABLE forward 2>/dev/null | grep -c "comment \"NAT-${port}-tcp" || echo 0)
udp_count=$($NFT list chain ip $TABLE forward 2>/dev/null | grep -c "comment \"NAT-${port}-udp" || echo 0)
if [[ $tcp_count -gt 4 || $udp_count -gt 4 ]]; then
echo "[*] 清理端口 $port 的可能重复规则"
local info rip rport
info=$($NFT list chain ip $TABLE forward 2>/dev/null | grep -E "comment \"NAT-${port}-tcp.*\"" | head -1)
rip=$(echo "$info" | grep -oE 'ip (saddr|daddr) [0-9.]+' | awk '{print $3}')
rport=$(echo "$info" | grep -oE '(dport|sport) [0-9]+' | awk '{print $2}')
if [[ -n "$rip" && -n "$rport" ]]; then
del_rule "$port"
add_rule "$port" "$rip:$rport" # 默认不限速重建;需要限速再 add --rate
cleaned=$((cleaned+1))
fi
fi
done
[[ $cleaned -eq 0 ]] && echo "[*] 没有发现需要清理的重复规则" || echo "[+] 清理了 $cleaned 个端口"
show_rules
}
list_all() {
echo "============== 详细规则列表 =============="
echo "--- PREROUTING ---"; $NFT list chain ip $TABLE prerouting 2>/dev/null | grep -E "(dnat|comment)" || echo "无规则"
echo "--- POSTROUTING ---"; $NFT list chain ip $TABLE postrouting 2>/dev/null | grep -E "(masquerade|comment)" || echo "无规则"
echo "--- FORWARD ---"; $NFT list chain ip $TABLE forward 2>/dev/null | grep -E "(limit|accept|drop|comment)" || echo "无规则"
echo "========================================"
}
reset_all() {
echo "[!] 警告:这将删除所有 NAT 规则!"
read -r -p "确认继续?(y/N): " confirm
if [[ "$confirm" == [yY] ]]; then
$NFT delete table ip $TABLE 2>/dev/null || echo "[*] 表不存在或已删除"
init_table; save_rules; echo "[+] 所有规则已清空"
else
echo "[*] 操作已取消"
fi
}
show_help() {
cat <<EOF
NAT 转发管理脚本 (nftables + 端口限速,双向)
用法:
$0 show
$0 add <LOCAL_PORT> <IP:PORT> [--rate Mbps]
示例:
$0 add 4443 1.1.1.1:443 # 不限速
$0 add 4443 1.1.1.1:443 --rate 10 # 上/下行各限 10Mbps
$0 del <LOCAL_PORT>
$0 cleanup
$0 list-all
$0 reset
说明:
- 限速=两套规则:去程(daddr:rport) 与 回程(saddr:sport);超额 drop(硬卡带宽)。
- 单位:Mbps -> kbytes/second(1 Mbps = 125 kB/s),burst: TCP=5MB, UDP=2MB。
EOF
}
init_table
case "$1" in
show) show_rules ;;
add) shift; parse_add_args "$@"; add_rule "$ADD_LPORT" "$ADD_REMOTE" "$ADD_RATE" ;;
del)
if [[ $# -ne 2 ]]; then echo "错误:参数不足"; show_help; exit 1; fi
del_rule "$2"; show_rules ;;
cleanup) cleanup_rules ;;
list-all) list_all ;;
reset) reset_all ;;
*) show_help; exit 1 ;;
esac
使用说明:
~ ./nat-shaper.sh --help
NAT 转发管理脚本 (nftables + 端口限速,双向)
用法:
./nat-shaper.sh show
./nat-shaper.sh add <LOCAL_PORT> <IP:PORT> [--rate Mbps]
示例:
./nat-shaper.sh add 4443 1.1.1.1:443 # 不限速
./nat-shaper.sh add 4443 1.1.1.1:443 --rate 10 # 上/下行各限 10Mbps
./nat-shaper.sh del <LOCAL_PORT>
./nat-shaper.sh cleanup
./nat-shaper.sh list-all
./nat-shaper.sh reset
说明:
- 限速=两套规则:去程(daddr:rport) 与 回程(saddr:sport);超额 drop(硬卡带宽)。
- 单位:Mbps -> kbytes/second(1 Mbps = 125 kB/s),burst: TCP=5MB, UDP=2MB。
然后执行以下命令:
# 添加转发规则,将本地 8080 端口转发到 1.2.3.4:1234
add-nat.sh add 8080 1.2.3.4:1234
# 删除转发规则,删除本地 8080 端口的转发
add-nat.sh del 8080
# 查看当前转发情况
add-nat.sh show
# 清理重复规则
add-nat.sh cleanup
# 显示所有规则详情
add-nat.sh list-all
# 重置所有规则
add-nat.sh reset