Docker 容器外的 VPN (SNX) 内无法访问服务器
Server not reachable within a VPN (SNX) out of a Docker container
我正在使用带有内核的最新 Manjaro:x86_64 Linux 5.10.15-1-MANJARO。
我通过 VPN 连接到公司网络。
为此,我将 SNX 与构建版本 800010003 一起使用。
当我启动一个 Docker 容器(Docker 版本 20.10.3,内部版本 48d30b5b32),它应该从公司网络连接到一台机器时,我收到以下消息。
[maurice@laptop ~]$ docker run --rm alpine ping company-server
ping: bad address 'company-server'
同样使用来自 'company-server' 的 IP 也不起作用。
无论使用名称还是 IP,容器外部的 ping 都有效。
resolv.conf 在我看来是正确的。
[maurice@laptop ~]$ docker run --rm alpine cat /etc/resolv.conf
# Generated by NetworkManager
search lan
nameserver 10.1.0.250
nameserver 10.1.0.253
nameserver 192.168.86.1
到目前为止我发现了什么。
如果我将包 glibc 和 lib32-glibc 降级到版本 2.32-5,容器的 ping 将再次起作用。由于依赖关系,我还必须将 gcc、gcc-libs 和 lib32-gcc-libs 降级到版本 10.2.0-4。
我尝试了全新的 Pop OS 20.10 安装,同样的问题。
我还使用另一个运行良好的 VPN (OpenVPN) 进行了测试。但是,这只是一个测试场景,不能用作替代方案。
几天来我一直在寻找解决方案,但一无所获。如果有人能帮助我,那就太好了。
我现在遇到同样的问题。没什么大变化,但 tunsnx 接口范围从全局更改为 247。删除它并重新创建全局范围。
长话短说:
在内核 >5.8 上,不再使用全局范围创建 tunsnx 接口,需要重新创建。救援的小脚本 https://gist.github.com/Fahl-Design/ec1e066ec2ef8160d101dff96a9b56e8
更长的版本:
这是我的发现和(临时)修复它的解决方案:
重现步骤:
连接你的 snx 隧道
看到 ping 隧道后面的服务器失败
docker run --rm -ti --net=company_net busybox /bin/sh -c "ping 192.168.210.210"
运行 此命令用于检查“tunsnx”接口的 ip 和范围
ip -o address show "tunsnx" | awk -F ' +' '{print " " " " }'
如果你得到类似
的东西
192.168.210.XXX 192.168.210.30/32 247
或(Thx Timz)
192.168.210.XXX 192.168.210.30/32 nowhere
范围未设置为“全局”,无法建立连接
要解决此问题,如建议的“ronan lanore”,您需要将范围更改为全局
这可以通过像这样的一个小帮助脚本来完成:
#!/usr/bin/env bash
#
# Usage: [dry_run=1] [debug=1] [interface=tunsnx] docker-fix-snx
#
# Credits to: https://github.com/docker/for-linwux/issues/288#issuecomment-825580160
#
# Env Variables:
# interface - Defaults to tunsnx
# dry_run - Set to 1 to have a dry run, just printing out the iptables command
# debug - Set to 1 to see bash substitutions
set -eu
_log_stderr() {
echo "$*" >&2
}
if [ "${debug:=0}" = 1 ]; then
set -x
dry_run=${dry_run:=1}
fi
: ${dry_run:=0}
: ${interface:=tunsnx}
data=($(ip -o address show "$interface" | awk -F ' +' '{print " " " " }'))
LOCAL_ADDRESS_INDEX=0
PEER_ADDRESS_INDEX=1
SCOPE_INDEX=2
if [ "$dry_run" = 1 ]; then
echo "[-] DRY-RUN MODE"
fi
if [ "${data[$SCOPE_INDEX]}" == "global" ]; then
echo "[+] Interface ${interface} is already set to global scope. Skip!"
exit 0
else
echo "[+] Interface ${interface} is set to scope ${data[$SCOPE_INDEX]}."
tmpfile=$(mktemp --suffix=snxwrapper-routes)
echo "[+] Saving current IP routing table..."
if [ "$dry_run" = 0 ]; then
sudo ip route save >$tmpfile
fi
echo "[+] Deleting current interface ${interface}..."
if [ "$dry_run" = 0 ]; then
sudo ip address del ${data[$LOCAL_ADDRESS_INDEX]} peer ${data[$PEER_ADDRESS_INDEX]} dev ${interface}
fi
echo "[+] Recreating interface ${interface} with global scope..."
if [ "$dry_run" = 0 ]; then
sudo ip address add ${data[$LOCAL_ADDRESS_INDEX]} dev ${interface} peer ${data[$PEER_ADDRESS_INDEX]} scope global
fi
echo "[+] Restoring routing table..."
if [ "$dry_run" = 0 ]; then
sudo ip route restore <$tmpfile 2>/dev/null
fi
echo "[+] Cleaning temporary files..."
rm $tmpfile
echo "[+] Interface ${interface} is set to global scope. Done!"
if [ "$dry_run" = 0 ]; then
echo "[+] Result:"
ip -o address show "tunsnx" | awk -F ' +' '{print " " " " }'
fi
exit 0
fi
[ "$debug" = 1 ] && set +x
我正在使用带有内核的最新 Manjaro:x86_64 Linux 5.10.15-1-MANJARO。
我通过 VPN 连接到公司网络。 为此,我将 SNX 与构建版本 800010003 一起使用。
当我启动一个 Docker 容器(Docker 版本 20.10.3,内部版本 48d30b5b32),它应该从公司网络连接到一台机器时,我收到以下消息。
[maurice@laptop ~]$ docker run --rm alpine ping company-server ping: bad address 'company-server'
同样使用来自 'company-server' 的 IP 也不起作用。
无论使用名称还是 IP,容器外部的 ping 都有效。
resolv.conf 在我看来是正确的。
[maurice@laptop ~]$ docker run --rm alpine cat /etc/resolv.conf # Generated by NetworkManager search lan nameserver 10.1.0.250 nameserver 10.1.0.253 nameserver 192.168.86.1
到目前为止我发现了什么。
如果我将包 glibc 和 lib32-glibc 降级到版本 2.32-5,容器的 ping 将再次起作用。由于依赖关系,我还必须将 gcc、gcc-libs 和 lib32-gcc-libs 降级到版本 10.2.0-4。
我尝试了全新的 Pop OS 20.10 安装,同样的问题。 我还使用另一个运行良好的 VPN (OpenVPN) 进行了测试。但是,这只是一个测试场景,不能用作替代方案。
几天来我一直在寻找解决方案,但一无所获。如果有人能帮助我,那就太好了。
我现在遇到同样的问题。没什么大变化,但 tunsnx 接口范围从全局更改为 247。删除它并重新创建全局范围。
长话短说: 在内核 >5.8 上,不再使用全局范围创建 tunsnx 接口,需要重新创建。救援的小脚本 https://gist.github.com/Fahl-Design/ec1e066ec2ef8160d101dff96a9b56e8
更长的版本:
这是我的发现和(临时)修复它的解决方案:
重现步骤:
连接你的 snx 隧道
看到 ping 隧道后面的服务器失败
docker run --rm -ti --net=company_net busybox /bin/sh -c "ping 192.168.210.210"
运行 此命令用于检查“tunsnx”接口的 ip 和范围
ip -o address show "tunsnx" | awk -F ' +' '{print " " " " }'
如果你得到类似
的东西192.168.210.XXX 192.168.210.30/32 247
或(Thx Timz)
192.168.210.XXX 192.168.210.30/32 nowhere
范围未设置为“全局”,无法建立连接
要解决此问题,如建议的“ronan lanore”,您需要将范围更改为全局
这可以通过像这样的一个小帮助脚本来完成:
#!/usr/bin/env bash
#
# Usage: [dry_run=1] [debug=1] [interface=tunsnx] docker-fix-snx
#
# Credits to: https://github.com/docker/for-linwux/issues/288#issuecomment-825580160
#
# Env Variables:
# interface - Defaults to tunsnx
# dry_run - Set to 1 to have a dry run, just printing out the iptables command
# debug - Set to 1 to see bash substitutions
set -eu
_log_stderr() {
echo "$*" >&2
}
if [ "${debug:=0}" = 1 ]; then
set -x
dry_run=${dry_run:=1}
fi
: ${dry_run:=0}
: ${interface:=tunsnx}
data=($(ip -o address show "$interface" | awk -F ' +' '{print " " " " }'))
LOCAL_ADDRESS_INDEX=0
PEER_ADDRESS_INDEX=1
SCOPE_INDEX=2
if [ "$dry_run" = 1 ]; then
echo "[-] DRY-RUN MODE"
fi
if [ "${data[$SCOPE_INDEX]}" == "global" ]; then
echo "[+] Interface ${interface} is already set to global scope. Skip!"
exit 0
else
echo "[+] Interface ${interface} is set to scope ${data[$SCOPE_INDEX]}."
tmpfile=$(mktemp --suffix=snxwrapper-routes)
echo "[+] Saving current IP routing table..."
if [ "$dry_run" = 0 ]; then
sudo ip route save >$tmpfile
fi
echo "[+] Deleting current interface ${interface}..."
if [ "$dry_run" = 0 ]; then
sudo ip address del ${data[$LOCAL_ADDRESS_INDEX]} peer ${data[$PEER_ADDRESS_INDEX]} dev ${interface}
fi
echo "[+] Recreating interface ${interface} with global scope..."
if [ "$dry_run" = 0 ]; then
sudo ip address add ${data[$LOCAL_ADDRESS_INDEX]} dev ${interface} peer ${data[$PEER_ADDRESS_INDEX]} scope global
fi
echo "[+] Restoring routing table..."
if [ "$dry_run" = 0 ]; then
sudo ip route restore <$tmpfile 2>/dev/null
fi
echo "[+] Cleaning temporary files..."
rm $tmpfile
echo "[+] Interface ${interface} is set to global scope. Done!"
if [ "$dry_run" = 0 ]; then
echo "[+] Result:"
ip -o address show "tunsnx" | awk -F ' +' '{print " " " " }'
fi
exit 0
fi
[ "$debug" = 1 ] && set +x