-
Notifications
You must be signed in to change notification settings - Fork 30
Open
Description
起因
被控机为 Azure,Debian 12,安装了 tailscale
添加 iptables 转发规则,将 TCP 65432 端口转发到 1.1.1.1:443,发现端口不通
问题
运行 iptables -t nat -L -v --line-numbers
,结果如下:
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 615 44670 ts-postrouting all -- any any anywhere anywhere
2 65587 4056K MASQUERADE all -- any !docker0 172.17.0.0/16 anywhere
3 0 0 MASQUERADE tcp -- any any 172.17.0.3 172.17.0.3 tcp dpt:2222
4 0 0 SNAT tcp -- any any anywhere one.one.one.one tcp dpt:https /* BACKWARD 65432->1.1.1.1:443 */ to:100.123.x.x
5 0 0 SNAT tcp -- any any anywhere one.one.one.one tcp dpt:https /* BACKWARD 65432->1.1.1.1:443 */ to:10.1.0.4
6 0 0 SNAT tcp -- any any anywhere one.one.one.one tcp dpt:https /* BACKWARD 65432->1.1.1.1:443 */ to:172.17.0.1
可以看到,出现了多条 SNAT 规则,导致源 IP 没有被正确地替换为 eth0 的 IP 10.1.0.4
查阅源码中的脚本,发现问题所在:
get_ips () {
install_ip
IFACE=$(ip route show | grep default | grep metric | awk -F 'dev ' '{print $2}' | awk '{print $1}')
INET=$(ip address show $IFACE scope global | awk '/inet / {split($2,var,"/"); print var[1]}')
INET=$(echo $INET | xargs -n 1 | grep -Eo "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" | sort -u)
}
forward4 () {
[[ -z $INET ]] && echo "No valid interface ipv4 addresses found" && exit 1
if [[ $TYPE == "ALL" || $TYPE == "TCP" ]]
then
for SNATIP in $INET; do
$SUDO iptables -t nat -A POSTROUTING -d $REMOTE_IP -p tcp --dport $REMOTE_PORT -j SNAT --to-source $SNATIP -m comment --comment "BACKWARD $LOCAL_PORT->$REMOTE_IP:$REMOTE_PORT"
done
$SUDO iptables -t nat -A PREROUTING -p tcp --dport $LOCAL_PORT -j DNAT --to-destination $REMOTE_IP:$REMOTE_PORT -m comment --comment "FORWARD $LOCAL_PORT->$REMOTE_IP:$REMOTE_PORT"
# for ipt port traffic monitor
$SUDO iptables -I FORWARD -p tcp -d $REMOTE_IP --dport $REMOTE_PORT -j ACCEPT -m comment --comment "UPLOAD $LOCAL_PORT->$REMOTE_IP:$REMOTE_PORT"
$SUDO iptables -I FORWARD -p tcp -s $REMOTE_IP -j ACCEPT -m comment --comment "DOWNLOAD $LOCAL_PORT->$REMOTE_IP:$REMOTE_PORT"
fi
if [[ $TYPE == "ALL" || $TYPE == "UDP" ]]
then
for SNATIP in $INET; do
$SUDO iptables -t nat -A POSTROUTING -d $REMOTE_IP -p udp --dport $REMOTE_PORT -j SNAT --to-source $SNATIP -m comment --comment "BACKWARD $LOCAL_PORT->$REMOTE_IP:$REMOTE_PORT"
done
$SUDO iptables -t nat -A PREROUTING -p udp --dport $LOCAL_PORT -j DNAT --to-destination $REMOTE_IP:$REMOTE_PORT -m comment --comment "FORWARD $LOCAL_PORT->$REMOTE_IP:$REMOTE_PORT"
# for ipt port traffic monitor
$SUDO iptables -I FORWARD -p udp -d $REMOTE_IP --dport $REMOTE_PORT -j ACCEPT -m comment --comment "UPLOAD-UDP $LOCAL_PORT->$REMOTE_IP:$REMOTE_PORT"
$SUDO iptables -I FORWARD -p udp -s $REMOTE_IP -j ACCEPT -m comment --comment "DOWNLOAD-UDP $LOCAL_PORT->$REMOTE_IP:$REMOTE_PORT"
fi
}
脚本试图通过 ip route show | grep default | grep metric | awk -F 'dev ' '{print $2}' | awk '{print $1}
过滤中默认路由对应的网卡,之后再获取正确的源 IP,问题在于路由中不一定有 metric
,例如我这台 Azure 上的 ip route 输出:
default via 10.1.0.1 dev eth0
......
这导致没有获取到网卡,之后就获取到了多个源 IP,产生错误
解决方案
作为用户,最简单的解决方案是在被控机上安装 ifmetric
,然后运行:
ifmetric eth0 1
这样路由会变成:
default via 10.1.0.1 dev eth0 metric 1
这样就能正确获取到 IP 了。注意,如果你有多个路由,依靠 metric 确定优先级,这样可能会有副作用!请先研究清楚再操作
开发者可以考虑将面板脚本中的代码修改为:ip route show | grep default | awk -F 'dev ' '{print $2}' | awk '{print $1}
,或者干脆直接用 MASQUERADE?这样源 IP 就无所谓了
Metadata
Metadata
Assignees
Labels
No labels