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