Redsocks:修订间差异
跳转到导航
跳转到搜索
创建页面,内容为“<syntaxhighlight lang="bash" line="1"> #!/usr/bin/env bash set -euo pipefail ### ================= 基本配置 ================= REDSOCKS_CONF="/etc/redsocks.conf" REDSOCKS_BIN="/usr/sbin/redsocks" # 源码版可能是 /usr/local/bin/redsocks REDSOCKS_PORT=12345 CHAIN="NETPROXY" MARK="0x1" STATE_DIR="/run/netproxy" IPTABLES_BACKUP="$STATE_DIR/iptables.bak" ### ================= 工具函数 ================= die() { echo "[ERROR] $*" >&2 exit 1…” |
无编辑摘要 标签:2017年版源代码编辑 |
||
| 第1行: | 第1行: | ||
= Redsocks 透明代理安装配置 = | |||
== 概述 == | |||
本文用于在麒麟、Ubuntu 或 Debian 系统上部署基于 '''systemd + redsocks + iptables''' 的透明 TCP 代理。 | |||
流量路径如下: | |||
### ================= 工具函数 ================= | <pre> | ||
die() { | 本机 TCP 流量 | ||
│ | |||
▼ | |||
iptables OUTPUT | |||
│ | |||
▼ | |||
NETPROXY | |||
│ | |||
▼ | |||
redsocks 127.0.0.1:12345 | |||
│ | |||
▼ | |||
SOCKS5 10.8.30.135:10810 | |||
│ | |||
▼ | |||
目标服务器 | |||
</pre> | |||
'''警告:'''启用服务后会接管本机几乎全部 IPv4 TCP 流量。若通过 SSH 远程操作,可能导致 SSH 连接中断。建议通过本地终端执行,或者提前配 | |||
置管理网段放行规则。 | |||
== 部署参数 == | |||
{| class="wikitable" | |||
! 配置项 | |||
! 配置值 | |||
|- | |||
| 上游代理类型 | |||
| SOCKS5 | |||
|- | |||
| 上游代理地址 | |||
| <code>10.8.30.135:10810</code> | |||
|- | |||
| redsocks 本地地址 | |||
| <code>127.0.0.1:12345</code> | |||
|- | |||
| iptables 链 | |||
| <code>NETPROXY</code> | |||
|- | |||
| systemd 服务 | |||
| <code>proxy.service</code> | |||
|- | |||
| 管理脚本 | |||
| <code>/opt/netproxy/netproxy.sh</code> | |||
|- | |||
| redsocks 配置 | |||
| <code>/etc/redsocks.conf</code> | |||
|- | |||
| 防火墙备份 | |||
| <code>/run/netproxy/iptables.bak</code> | |||
|} | |||
== 1. 检查上游 SOCKS5 == | |||
先检查到上游代理的路由: | |||
<pre> | |||
ip route get 10.8.30.135 | |||
</pre> | |||
通过上游 SOCKS5 代理执行一次访问测试: | |||
<pre> | |||
curl \ | |||
--socks5-hostname 10.8.30.135:10810 \ | |||
--connect-timeout 5 \ | |||
--max-time 15 \ | |||
-I https://example.com | |||
</pre> | |||
如果测试失败,不要继续启用透明代理。应先检查: | |||
* 上游代理地址和端口是否正确。 | |||
* 本机到 <code>10.8.30.135</code> 的网络是否可达。 | |||
* 防火墙是否允许访问 TCP 端口 <code>10810</code>。 | |||
* 上游服务是否确实为 SOCKS5 服务。 | |||
== 2. 安装依赖 == | |||
<pre> | |||
sudo apt-get update | |||
sudo apt-get install -y redsocks iptables | |||
</pre> | |||
检查安装结果: | |||
<pre> | |||
/usr/sbin/redsocks -v | |||
iptables --version | |||
</pre> | |||
系统软件包自带一个 <code>redsocks.service</code>。自定义服务不能与它同时管理 redsocks,因此需要禁用: | |||
<pre> | |||
sudo systemctl disable --now redsocks.service | |||
</pre> | |||
确认系统服务状态: | |||
<pre> | |||
systemctl status redsocks.service --no-pager | |||
</pre> | |||
预期状态为: | |||
<pre> | |||
inactive (dead) | |||
</pre> | |||
== 3. 创建代理管理脚本 == | |||
创建程序目录: | |||
<pre> | |||
sudo install -d -o root -g root -m 0755 /opt/netproxy | |||
</pre> | |||
编辑管理脚本: | |||
<pre> | |||
sudoedit /opt/netproxy/netproxy.sh | |||
</pre> | |||
写入以下完整内容: | |||
<pre> | |||
#!/usr/bin/env bash | |||
set -euo pipefail | |||
### ================= 基本配置 ================= | |||
REDSOCKS_CONF="/etc/redsocks.conf" | |||
REDSOCKS_BIN="/usr/sbin/redsocks" | |||
REDSOCKS_PORT=12345 | |||
CHAIN="NETPROXY" | |||
MARK="0x1" | |||
STATE_DIR="/run/netproxy" | |||
IPTABLES_BACKUP="${STATE_DIR}/iptables.bak" | |||
### ================= 工具函数 ================= | |||
die() { | |||
echo "[ERROR] $*" >&2 | echo "[ERROR] $*" >&2 | ||
exit 1 | exit 1 | ||
} | } | ||
need_root() { | |||
[[ ${EUID} -eq 0 ]] || die "Must run as root" | |||
} | |||
ensure_dependencies() { | |||
[[ $ | [[ -x "${REDSOCKS_BIN}" ]] || | ||
die "redsocks not found: ${REDSOCKS_BIN}" | |||
ensure_dirs() { | command -v iptables >/dev/null || | ||
die "iptables not found" | |||
} | |||
command -v iptables-save >/dev/null || | |||
die "iptables-save not found" | |||
command -v iptables-restore >/dev/null || | |||
die "iptables-restore not found" | |||
} | |||
ensure_dirs() { | |||
install -d -o root -g root -m 0755 "${STATE_DIR}" | |||
} | |||
parse_proxy() { | |||
[[ $# -eq 1 ]] || die "Missing proxy address" | |||
[[ "$1" =~ ^([^:]+):([0-9]+)$ ]] || | |||
die "Invalid proxy format, expected ip:port" | |||
PROXY_IP="${BASH_REMATCH[1]}" | PROXY_IP="${BASH_REMATCH[1]}" | ||
PROXY_PORT="${BASH_REMATCH[2]}" | PROXY_PORT="${BASH_REMATCH[2]}" | ||
if ((PROXY_PORT < 1 || PROXY_PORT > 65535)); then | |||
die "Invalid proxy port: ${PROXY_PORT}" | |||
fi | |||
} | |||
} | |||
redsocks | ### ================= redsocks ================= | ||
write_redsocks_conf() { | |||
cat >"${REDSOCKS_CONF}" <<EOF | |||
base { | |||
} | log_info = on; | ||
log = "syslog:daemon"; | |||
daemon = on; | |||
redirector = iptables; | |||
} | |||
redsocks { | |||
local_ip = 127.0.0.1; | |||
} | local_port = ${REDSOCKS_PORT}; | ||
ip = ${PROXY_IP}; | |||
port = ${PROXY_PORT}; | |||
type = socks5; | |||
} | |||
EOF | |||
chmod 0644 "${REDSOCKS_CONF}" | |||
} | |||
} | |||
start_redsocks() { | |||
# 本服务独占 redsocks,避免系统自带实例产生冲突。 | |||
pkill -x redsocks 2>/dev/null || true | |||
"${REDSOCKS_BIN}" -t -c "${REDSOCKS_CONF}" | |||
"${REDSOCKS_BIN}" -c "${REDSOCKS_CONF}" | |||
} | |||
stop_redsocks() { | |||
pkill -x redsocks 2>/dev/null || true | |||
} | |||
### ================= iptables ================= | |||
iptables_save() { | |||
iptables - | iptables-save >"${IPTABLES_BACKUP}" | ||
chmod 0600 "${IPTABLES_BACKUP}" | |||
} | |||
iptables_restore() { | |||
iptables - | [[ -f "${IPTABLES_BACKUP}" ]] || return 1 | ||
iptables-restore <"${IPTABLES_BACKUP}" | |||
} | |||
iptables_apply() { | |||
iptables -t nat - | iptables -t nat -N "${CHAIN}" 2>/dev/null || true | ||
iptables -t nat -F "${CHAIN}" | |||
# | # 放行已标记的 redsocks 返回流量,避免循环代理。 | ||
iptables -t | iptables -t nat -A "${CHAIN}" \ | ||
-m mark --mark "${MARK}" -j RETURN | |||
} | |||
# 回环流量不代理。 | |||
iptables -t nat - | iptables -t nat -A "${CHAIN}" \ | ||
-d 127.0.0.0/8 -j RETURN | |||
iptables -t | # 上游 SOCKS5 服务器必须直连,避免代理回环。 | ||
iptables -t nat -A "${CHAIN}" \ | |||
-d "${PROXY_IP}" -j RETURN | |||
### ================= 命令实现 ================= | # 其余本机 IPv4 TCP 流量重定向到 redsocks。 | ||
cmd_start() { | iptables -t nat -A "${CHAIN}" \ | ||
-p tcp -j REDIRECT --to-ports "${REDSOCKS_PORT}" | |||
# 只处理本机产生的连接,不处理转发流量。 | |||
iptables -t nat -C OUTPUT \ | |||
-p tcp -j "${CHAIN}" 2>/dev/null || | |||
iptables -t nat -A OUTPUT \ | |||
-p tcp -j "${CHAIN}" | |||
# 标记 redsocks 本地返回流量。 | |||
iptables -t mangle -C OUTPUT \ | |||
-p tcp --sport "${REDSOCKS_PORT}" \ | |||
-j MARK --set-mark "${MARK}" 2>/dev/null || | |||
iptables -t mangle -A OUTPUT \ | |||
-p tcp --sport "${REDSOCKS_PORT}" \ | |||
-j MARK --set-mark "${MARK}" | |||
} | |||
iptables_clear() { | |||
iptables -t nat -D OUTPUT \ | |||
-p tcp -j "${CHAIN}" 2>/dev/null || true | |||
iptables -t nat -F "${CHAIN}" 2>/dev/null || true | |||
iptables -t nat -X "${CHAIN}" 2>/dev/null || true | |||
iptables -t mangle -D OUTPUT \ | |||
-p tcp --sport "${REDSOCKS_PORT}" \ | |||
-j MARK --set-mark "${MARK}" 2>/dev/null || true | |||
} | |||
### ================= 命令实现 ================= | |||
cmd_start() { | |||
parse_proxy "$1" | parse_proxy "$1" | ||
ensure_dependencies | |||
ensure_dirs | ensure_dirs | ||
iptables_save | iptables_save | ||
write_redsocks_conf | write_redsocks_conf | ||
start_redsocks | start_redsocks | ||
cmd_stop() { | if ! iptables_apply; then | ||
stop_redsocks | |||
iptables_restore || iptables_clear | |||
die "Failed to apply iptables rules" | |||
fi | |||
echo "[OK] netproxy started via ${PROXY_IP}:${PROXY_PORT}" | |||
} | |||
cmd_stop() { | |||
stop_redsocks | stop_redsocks | ||
cmd_status() { | if ! iptables_restore; then | ||
iptables_clear | |||
fi | |||
rm -f "${IPTABLES_BACKUP}" | |||
rmdir "${STATE_DIR}" 2>/dev/null || true | |||
echo "[OK] netproxy stopped and firewall restored" | |||
} | |||
cmd_status() { | |||
echo "=== redsocks ===" | echo "=== redsocks ===" | ||
pgrep redsocks >/dev/null | if pgrep -x redsocks >/dev/null; then | ||
echo "running" | |||
pgrep -a -x redsocks | |||
else | |||
echo "stopped" | |||
fi | |||
echo | |||
echo "=== listen port ===" | |||
ss -ltn | grep ":${REDSOCKS_PORT} " || | |||
echo "port ${REDSOCKS_PORT} not listening" | |||
echo | echo | ||
echo "=== iptables nat ===" | echo "=== iptables nat ===" | ||
iptables -t nat -S | grep "$CHAIN" || echo "no netproxy nat rules" | iptables -t nat -S | grep "${CHAIN}" || | ||
echo "no netproxy nat rules" | |||
echo | echo | ||
echo "=== iptables mangle ===" | echo "=== iptables mangle ===" | ||
iptables -t mangle -S | grep "$REDSOCKS_PORT" || echo "no netproxy mangle rules" | iptables -t mangle -S | | ||
} | grep -- "--sport ${REDSOCKS_PORT}" || | ||
echo "no netproxy mangle rules" | |||
} | |||
### ================= 主入口 ================= | ### ================= 主入口 ================= | ||
case "${1:-}" in | need_root | ||
case "${1:-}" in | |||
start) | start) | ||
[[ $# -eq 2 ]] || | |||
die "Usage: $0 start ip:port" | |||
cmd_start "$2" | |||
;; | |||
stop) | stop) | ||
cmd_stop | [[ $# -eq 1 ]] || | ||
die "Usage: $0 stop" | |||
cmd_stop | |||
;; | |||
status) | status) | ||
cmd_status | [[ $# -eq 1 ]] || | ||
die "Usage: $0 status" | |||
cmd_status | |||
;; | |||
*) | *) | ||
echo "Usage:" | |||
echo " $0 start ip:port" | |||
echo " $0 stop" | |||
echo " $0 status" | |||
exit 1 | |||
;; | |||
esac | esac | ||
</pre> | |||
设置文件权限: | |||
<pre> | |||
sudo chown root:root /opt/netproxy/netproxy.sh | |||
sudo chmod 0755 /opt/netproxy/netproxy.sh | |||
</pre> | |||
检查 Bash 语法: | |||
<pre> | |||
bash -n /opt/netproxy/netproxy.sh | |||
</pre> | |||
命令没有输出即表示语法检查通过。 | |||
== 4. 可选:配置直连网段 == | |||
当前脚本除回环地址和上游代理外,会代理所有本机 IPv4 TCP 流量,包括内网地址。 | |||
如果需要保持管理网段直连,在 <code>iptables_apply()</code> 函数中、“上游 SOCKS5 服务器必须直连”规则之后加入: | |||
<pre> | |||
iptables -t nat -A "${CHAIN}" \ | |||
-d 192.168.220.0/24 -j RETURN | |||
</pre> | |||
也可以根据实际环境放行常见私有网段: | |||
<pre> | |||
iptables -t nat -A "${CHAIN}" -d 10.0.0.0/8 -j RETURN | |||
iptables -t nat -A "${CHAIN}" -d 172.16.0.0/12 -j RETURN | |||
iptables -t nat -A "${CHAIN}" -d 192.168.0.0/16 -j RETURN | |||
</pre> | |||
如果内网业务本来就需要通过 SOCKS5 代理访问,则不要添加对应的放行规则。 | |||
== 5. 创建 systemd 服务 == | |||
编辑服务文件: | |||
<pre> | |||
sudoedit /etc/systemd/system/proxy.service | |||
</pre> | |||
写入以下内容: | |||
<pre> | |||
[Unit] | |||
Description=Proxy Service (Redsocks) | |||
Wants=network-online.target | |||
After=network-online.target | |||
Conflicts=redsocks.service | |||
[Service] | |||
Type=forking | |||
ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.135:10810 | |||
ExecStop=/opt/netproxy/netproxy.sh stop | |||
Restart=on-failure | |||
RestartSec=5s | |||
TimeoutStartSec=30s | |||
TimeoutStopSec=30s | |||
[Install] | |||
WantedBy=multi-user.target | |||
</pre> | |||
设置文件权限: | |||
<pre> | |||
sudo chown root:root /etc/systemd/system/proxy.service | |||
sudo chmod 0644 /etc/systemd/system/proxy.service | |||
</pre> | |||
检查 systemd 配置: | |||
<pre> | |||
sudo systemd-analyze verify /etc/systemd/system/proxy.service | |||
</pre> | |||
== 6. 加载并启动服务 == | |||
'''警告:'''执行以下命令后会立即接管本机 IPv4 TCP 流量。 | |||
重新加载 systemd: | |||
<pre> | |||
sudo systemctl daemon-reload | |||
</pre> | |||
设置开机启动并立即启动服务: | |||
<pre> | |||
sudo systemctl enable --now proxy.service | |||
</pre> | |||
检查服务状态: | |||
<pre> | |||
systemctl is-enabled proxy.service | |||
systemctl is-active proxy.service | |||
systemctl status proxy.service --no-pager | |||
</pre> | |||
预期结果: | |||
<pre> | |||
enabled | |||
active | |||
</pre> | |||
== 7. 验证部署结果 == | |||
=== 7.1 检查 redsocks 和 iptables === | |||
<pre> | |||
sudo /opt/netproxy/netproxy.sh status | |||
</pre> | |||
预期输出类似: | |||
<pre> | |||
=== redsocks === | |||
running | |||
=== listen port === | |||
LISTEN ... 127.0.0.1:12345 ... | |||
=== iptables nat === | |||
-N NETPROXY | |||
-A OUTPUT -p tcp -j NETPROXY | |||
-A NETPROXY -m mark --mark 0x1 -j RETURN | |||
-A NETPROXY -d 127.0.0.0/8 -j RETURN | |||
-A NETPROXY -d 10.8.30.135/32 -j RETURN | |||
-A NETPROXY -p tcp -j REDIRECT --to-ports 12345 | |||
=== iptables mangle === | |||
-A OUTPUT -p tcp -m tcp --sport 12345 -j MARK --set-xmark 0x1/0xffffffff | |||
</pre> | |||
=== 7.2 检查监听端口 === | |||
<pre> | |||
sudo ss -ltnp 'sport = :12345' | |||
</pre> | |||
预期监听地址: | |||
<pre> | |||
127.0.0.1:12345 | |||
</pre> | |||
=== 7.3 检查完整规则顺序 === | |||
<pre> | |||
sudo iptables -t nat -S OUTPUT | |||
sudo iptables -t nat -S NETPROXY | |||
sudo iptables -t mangle -S OUTPUT | |||
</pre> | |||
如果本机还部署了其他透明代理,例如 <code>SSLPROXY</code>,应特别检查不同代理链在 <code>OUTPUT</code> 中的顺序。 | |||
=== 7.4 查看日志 === | |||
查看最近100条日志: | |||
<pre> | |||
sudo journalctl -u proxy.service -n 100 --no-pager | |||
</pre> | |||
持续观察日志: | |||
<pre> | |||
sudo journalctl -u proxy.service -f | |||
</pre> | |||
=== 7.5 测试 TCP 访问 === | |||
<pre> | |||
curl --connect-timeout 5 --max-time 15 -I https://example.com | |||
</pre> | |||
能够正常返回 HTTP 响应头,且 redsocks 日志中出现对应连接,说明透明代理工作正常。 | |||
== 8. 修改上游代理 == | |||
编辑服务文件: | |||
<pre> | |||
sudoedit /etc/systemd/system/proxy.service | |||
</pre> | |||
修改以下配置: | |||
<pre> | |||
ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.135:10810 | |||
</pre> | |||
例如,将上游代理修改为 <code>10.8.30.136:10811</code>: | |||
<pre> | |||
ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.136:10811 | |||
</pre> | |||
重新加载配置并重启: | |||
<pre> | |||
sudo systemctl daemon-reload | |||
sudo systemctl restart proxy.service | |||
sudo /opt/netproxy/netproxy.sh status | |||
</pre> | |||
== 9. 停止服务 == | |||
停止服务: | |||
<pre> | |||
sudo systemctl stop proxy.service | |||
</pre> | |||
停止后检查: | |||
<pre> | |||
sudo /opt/netproxy/netproxy.sh status | |||
</pre> | |||
== 10. 取消开机启动 == | |||
<pre> | |||
sudo systemctl disable --now proxy.service | |||
</pre> | |||
确认 NETPROXY 规则已清理: | |||
<pre> | |||
sudo iptables -t nat -S | grep NETPROXY || true | |||
sudo iptables -t mangle -S | grep 12345 || true | |||
pgrep -a -x redsocks || true | |||
</pre> | |||
== 11. 卸载自定义代理 == | |||
先停止并禁用服务: | |||
<pre> | |||
sudo systemctl disable --now proxy.service | |||
</pre> | |||
删除 systemd 服务和管理脚本: | |||
<pre> | |||
sudo rm /etc/systemd/system/proxy.service | |||
sudo rm /opt/netproxy/netproxy.sh | |||
sudo rmdir /opt/netproxy | |||
sudo systemctl daemon-reload | |||
sudo systemctl reset-failed | |||
</pre> | |||
如果需要恢复系统自带的 redsocks 服务: | |||
<pre> | |||
sudo systemctl enable --now redsocks.service | |||
</pre> | |||
== 注意事项 == | |||
</ | * 该方案只代理本机产生的 IPv4 TCP 流量。 | ||
* UDP、ICMP、IPv6 和转发流量不会经过该代理。 | |||
* DNS 使用 UDP 时仍会直接访问 DNS 服务器。 | |||
* QUIC、HTTP/3 等 UDP 协议不会经过 redsocks。 | |||
* <code>pkill -x redsocks</code> 会停止系统中所有名为 redsocks 的进程。 | |||
* 系统自带的 <code>redsocks.service</code> 应保持禁用,避免双实例冲突。 | |||
* 上游 SOCKS5 地址必须在 <code>NETPROXY</code> 中直接放行,否则会形成代理回环。 | |||
* 如果通过 SSH 部署,应提前放行管理地址或管理网段。 | |||
* 当前停止逻辑会恢复启动前保存的整份 iptables 快照。 | |||
* 如果服务运行期间其他程序修改了防火墙,停止服务可能覆盖这些修改。 | |||
* 生产环境建议只清理 <code>NETPROXY</code> 自己创建的规则,避免全量恢复 iptables。 | |||
* 不要混用 <code>iptables</code> 和 <code>iptables-legacy</code>,应确认其他安全软件使用的防火墙后端。 | |||
2026年8月12日 (三) 03:28的版本
Redsocks 透明代理安装配置
== 概述 ==
本文用于在麒麟、Ubuntu 或 Debian 系统上部署基于 systemd + redsocks + iptables 的透明 TCP 代理。
流量路径如下:
本机 TCP 流量
│
▼
iptables OUTPUT
│
▼
NETPROXY
│
▼
redsocks 127.0.0.1:12345
│
▼
SOCKS5 10.8.30.135:10810
│
▼
目标服务器
警告:启用服务后会接管本机几乎全部 IPv4 TCP 流量。若通过 SSH 远程操作,可能导致 SSH 连接中断。建议通过本地终端执行,或者提前配 置管理网段放行规则。
== 部署参数 ==
| 配置项 | 配置值 |
|---|---|
| 上游代理类型 | SOCKS5 |
| 上游代理地址 | 10.8.30.135:10810
|
| redsocks 本地地址 | 127.0.0.1:12345
|
| iptables 链 | NETPROXY
|
| systemd 服务 | proxy.service
|
| 管理脚本 | /opt/netproxy/netproxy.sh
|
| redsocks 配置 | /etc/redsocks.conf
|
| 防火墙备份 | /run/netproxy/iptables.bak
|
== 1. 检查上游 SOCKS5 ==
先检查到上游代理的路由:
ip route get 10.8.30.135
通过上游 SOCKS5 代理执行一次访问测试:
curl \
--socks5-hostname 10.8.30.135:10810 \
--connect-timeout 5 \
--max-time 15 \
-I https://example.com
如果测试失败,不要继续启用透明代理。应先检查:
* 上游代理地址和端口是否正确。 * 本机到10.8.30.135的网络是否可达。 * 防火墙是否允许访问 TCP 端口10810。 * 上游服务是否确实为 SOCKS5 服务。
== 2. 安装依赖 ==
sudo apt-get update sudo apt-get install -y redsocks iptables
检查安装结果:
/usr/sbin/redsocks -v iptables --version
系统软件包自带一个 redsocks.service。自定义服务不能与它同时管理 redsocks,因此需要禁用:
sudo systemctl disable --now redsocks.service
确认系统服务状态:
systemctl status redsocks.service --no-pager
预期状态为:
inactive (dead)
== 3. 创建代理管理脚本 ==
创建程序目录:
sudo install -d -o root -g root -m 0755 /opt/netproxy
编辑管理脚本:
sudoedit /opt/netproxy/netproxy.sh
写入以下完整内容:
#!/usr/bin/env bash
set -euo pipefail
### ================= 基本配置 =================
REDSOCKS_CONF="/etc/redsocks.conf"
REDSOCKS_BIN="/usr/sbin/redsocks"
REDSOCKS_PORT=12345
CHAIN="NETPROXY"
MARK="0x1"
STATE_DIR="/run/netproxy"
IPTABLES_BACKUP="${STATE_DIR}/iptables.bak"
### ================= 工具函数 =================
die() {
echo "[ERROR] $*" >&2
exit 1
}
need_root() {
[[ ${EUID} -eq 0 ]] || die "Must run as root"
}
ensure_dependencies() {
[[ -x "${REDSOCKS_BIN}" ]] ||
die "redsocks not found: ${REDSOCKS_BIN}"
command -v iptables >/dev/null ||
die "iptables not found"
command -v iptables-save >/dev/null ||
die "iptables-save not found"
command -v iptables-restore >/dev/null ||
die "iptables-restore not found"
}
ensure_dirs() {
install -d -o root -g root -m 0755 "${STATE_DIR}"
}
parse_proxy() {
[[ $# -eq 1 ]] || die "Missing proxy address"
[[ "$1" =~ ^([^:]+):([0-9]+)$ ]] ||
die "Invalid proxy format, expected ip:port"
PROXY_IP="${BASH_REMATCH[1]}"
PROXY_PORT="${BASH_REMATCH[2]}"
if ((PROXY_PORT < 1 || PROXY_PORT > 65535)); then
die "Invalid proxy port: ${PROXY_PORT}"
fi
}
### ================= redsocks =================
write_redsocks_conf() {
cat >"${REDSOCKS_CONF}" <<EOF
base {
log_info = on;
log = "syslog:daemon";
daemon = on;
redirector = iptables;
}
redsocks {
local_ip = 127.0.0.1;
local_port = ${REDSOCKS_PORT};
ip = ${PROXY_IP};
port = ${PROXY_PORT};
type = socks5;
}
EOF
chmod 0644 "${REDSOCKS_CONF}"
}
start_redsocks() {
# 本服务独占 redsocks,避免系统自带实例产生冲突。
pkill -x redsocks 2>/dev/null || true
"${REDSOCKS_BIN}" -t -c "${REDSOCKS_CONF}"
"${REDSOCKS_BIN}" -c "${REDSOCKS_CONF}"
}
stop_redsocks() {
pkill -x redsocks 2>/dev/null || true
}
### ================= iptables =================
iptables_save() {
iptables-save >"${IPTABLES_BACKUP}"
chmod 0600 "${IPTABLES_BACKUP}"
}
iptables_restore() {
[[ -f "${IPTABLES_BACKUP}" ]] || return 1
iptables-restore <"${IPTABLES_BACKUP}"
}
iptables_apply() {
iptables -t nat -N "${CHAIN}" 2>/dev/null || true
iptables -t nat -F "${CHAIN}"
# 放行已标记的 redsocks 返回流量,避免循环代理。
iptables -t nat -A "${CHAIN}" \
-m mark --mark "${MARK}" -j RETURN
# 回环流量不代理。
iptables -t nat -A "${CHAIN}" \
-d 127.0.0.0/8 -j RETURN
# 上游 SOCKS5 服务器必须直连,避免代理回环。
iptables -t nat -A "${CHAIN}" \
-d "${PROXY_IP}" -j RETURN
# 其余本机 IPv4 TCP 流量重定向到 redsocks。
iptables -t nat -A "${CHAIN}" \
-p tcp -j REDIRECT --to-ports "${REDSOCKS_PORT}"
# 只处理本机产生的连接,不处理转发流量。
iptables -t nat -C OUTPUT \
-p tcp -j "${CHAIN}" 2>/dev/null ||
iptables -t nat -A OUTPUT \
-p tcp -j "${CHAIN}"
# 标记 redsocks 本地返回流量。
iptables -t mangle -C OUTPUT \
-p tcp --sport "${REDSOCKS_PORT}" \
-j MARK --set-mark "${MARK}" 2>/dev/null ||
iptables -t mangle -A OUTPUT \
-p tcp --sport "${REDSOCKS_PORT}" \
-j MARK --set-mark "${MARK}"
}
iptables_clear() {
iptables -t nat -D OUTPUT \
-p tcp -j "${CHAIN}" 2>/dev/null || true
iptables -t nat -F "${CHAIN}" 2>/dev/null || true
iptables -t nat -X "${CHAIN}" 2>/dev/null || true
iptables -t mangle -D OUTPUT \
-p tcp --sport "${REDSOCKS_PORT}" \
-j MARK --set-mark "${MARK}" 2>/dev/null || true
}
### ================= 命令实现 =================
cmd_start() {
parse_proxy "$1"
ensure_dependencies
ensure_dirs
iptables_save
write_redsocks_conf
start_redsocks
if ! iptables_apply; then
stop_redsocks
iptables_restore || iptables_clear
die "Failed to apply iptables rules"
fi
echo "[OK] netproxy started via ${PROXY_IP}:${PROXY_PORT}"
}
cmd_stop() {
stop_redsocks
if ! iptables_restore; then
iptables_clear
fi
rm -f "${IPTABLES_BACKUP}"
rmdir "${STATE_DIR}" 2>/dev/null || true
echo "[OK] netproxy stopped and firewall restored"
}
cmd_status() {
echo "=== redsocks ==="
if pgrep -x redsocks >/dev/null; then
echo "running"
pgrep -a -x redsocks
else
echo "stopped"
fi
echo
echo "=== listen port ==="
ss -ltn | grep ":${REDSOCKS_PORT} " ||
echo "port ${REDSOCKS_PORT} not listening"
echo
echo "=== iptables nat ==="
iptables -t nat -S | grep "${CHAIN}" ||
echo "no netproxy nat rules"
echo
echo "=== iptables mangle ==="
iptables -t mangle -S |
grep -- "--sport ${REDSOCKS_PORT}" ||
echo "no netproxy mangle rules"
}
### ================= 主入口 =================
need_root
case "${1:-}" in
start)
[[ $# -eq 2 ]] ||
die "Usage: $0 start ip:port"
cmd_start "$2"
;;
stop)
[[ $# -eq 1 ]] ||
die "Usage: $0 stop"
cmd_stop
;;
status)
[[ $# -eq 1 ]] ||
die "Usage: $0 status"
cmd_status
;;
*)
echo "Usage:"
echo " $0 start ip:port"
echo " $0 stop"
echo " $0 status"
exit 1
;;
esac
设置文件权限:
sudo chown root:root /opt/netproxy/netproxy.sh sudo chmod 0755 /opt/netproxy/netproxy.sh
检查 Bash 语法:
bash -n /opt/netproxy/netproxy.sh
命令没有输出即表示语法检查通过。
== 4. 可选:配置直连网段 ==
当前脚本除回环地址和上游代理外,会代理所有本机 IPv4 TCP 流量,包括内网地址。
如果需要保持管理网段直连,在 iptables_apply() 函数中、“上游 SOCKS5 服务器必须直连”规则之后加入:
iptables -t nat -A "${CHAIN}" \
-d 192.168.220.0/24 -j RETURN
也可以根据实际环境放行常见私有网段:
iptables -t nat -A "${CHAIN}" -d 10.0.0.0/8 -j RETURN
iptables -t nat -A "${CHAIN}" -d 172.16.0.0/12 -j RETURN
iptables -t nat -A "${CHAIN}" -d 192.168.0.0/16 -j RETURN
如果内网业务本来就需要通过 SOCKS5 代理访问,则不要添加对应的放行规则。
== 5. 创建 systemd 服务 ==
编辑服务文件:
sudoedit /etc/systemd/system/proxy.service
写入以下内容:
[Unit] Description=Proxy Service (Redsocks) Wants=network-online.target After=network-online.target Conflicts=redsocks.service [Service] Type=forking ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.135:10810 ExecStop=/opt/netproxy/netproxy.sh stop Restart=on-failure RestartSec=5s TimeoutStartSec=30s TimeoutStopSec=30s [Install] WantedBy=multi-user.target
设置文件权限:
sudo chown root:root /etc/systemd/system/proxy.service sudo chmod 0644 /etc/systemd/system/proxy.service
检查 systemd 配置:
sudo systemd-analyze verify /etc/systemd/system/proxy.service
== 6. 加载并启动服务 ==
警告:执行以下命令后会立即接管本机 IPv4 TCP 流量。
重新加载 systemd:
sudo systemctl daemon-reload
设置开机启动并立即启动服务:
sudo systemctl enable --now proxy.service
检查服务状态:
systemctl is-enabled proxy.service systemctl is-active proxy.service systemctl status proxy.service --no-pager
预期结果:
enabled active
== 7. 验证部署结果 ==
=== 7.1 检查 redsocks 和 iptables ===
sudo /opt/netproxy/netproxy.sh status
预期输出类似:
=== redsocks === running === listen port === LISTEN ... 127.0.0.1:12345 ... === iptables nat === -N NETPROXY -A OUTPUT -p tcp -j NETPROXY -A NETPROXY -m mark --mark 0x1 -j RETURN -A NETPROXY -d 127.0.0.0/8 -j RETURN -A NETPROXY -d 10.8.30.135/32 -j RETURN -A NETPROXY -p tcp -j REDIRECT --to-ports 12345 === iptables mangle === -A OUTPUT -p tcp -m tcp --sport 12345 -j MARK --set-xmark 0x1/0xffffffff
=== 7.2 检查监听端口 ===
sudo ss -ltnp 'sport = :12345'
预期监听地址:
127.0.0.1:12345
=== 7.3 检查完整规则顺序 ===
sudo iptables -t nat -S OUTPUT sudo iptables -t nat -S NETPROXY sudo iptables -t mangle -S OUTPUT
如果本机还部署了其他透明代理,例如SSLPROXY,应特别检查不同代理链在OUTPUT中的顺序。
=== 7.4 查看日志 ===
查看最近100条日志:
sudo journalctl -u proxy.service -n 100 --no-pager
持续观察日志:
sudo journalctl -u proxy.service -f
=== 7.5 测试 TCP 访问 ===
curl --connect-timeout 5 --max-time 15 -I https://example.com
能够正常返回 HTTP 响应头,且 redsocks 日志中出现对应连接,说明透明代理工作正常。
== 8. 修改上游代理 ==
编辑服务文件:
sudoedit /etc/systemd/system/proxy.service
修改以下配置:
ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.135:10810
例如,将上游代理修改为 10.8.30.136:10811:
ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.136:10811
重新加载配置并重启:
sudo systemctl daemon-reload sudo systemctl restart proxy.service sudo /opt/netproxy/netproxy.sh status
== 9. 停止服务 ==
停止服务:
sudo systemctl stop proxy.service
停止后检查:
sudo /opt/netproxy/netproxy.sh status
== 10. 取消开机启动 ==
sudo systemctl disable --now proxy.service
确认 NETPROXY 规则已清理:
sudo iptables -t nat -S | grep NETPROXY || true sudo iptables -t mangle -S | grep 12345 || true pgrep -a -x redsocks || true
== 11. 卸载自定义代理 ==
先停止并禁用服务:
sudo systemctl disable --now proxy.service
删除 systemd 服务和管理脚本:
sudo rm /etc/systemd/system/proxy.service sudo rm /opt/netproxy/netproxy.sh sudo rmdir /opt/netproxy sudo systemctl daemon-reload sudo systemctl reset-failed
如果需要恢复系统自带的 redsocks 服务:
sudo systemctl enable --now redsocks.service
== 注意事项 ==
* 该方案只代理本机产生的 IPv4 TCP 流量。 * UDP、ICMP、IPv6 和转发流量不会经过该代理。 * DNS 使用 UDP 时仍会直接访问 DNS 服务器。 * QUIC、HTTP/3 等 UDP 协议不会经过 redsocks。 *pkill -x redsocks会停止系统中所有名为 redsocks 的进程。 * 系统自带的redsocks.service应保持禁用,避免双实例冲突。 * 上游 SOCKS5 地址必须在NETPROXY中直接放行,否则会形成代理回环。 * 如果通过 SSH 部署,应提前放行管理地址或管理网段。 * 当前停止逻辑会恢复启动前保存的整份 iptables 快照。 * 如果服务运行期间其他程序修改了防火墙,停止服务可能覆盖这些修改。 * 生产环境建议只清理NETPROXY自己创建的规则,避免全量恢复 iptables。 * 不要混用iptables和iptables-legacy,应确认其他安全软件使用的防火墙后端。