DNS 服务是由服务器提供的,许多公司和组织都提供 DNS 服务,比如 Google 的 8.8.8.8 等等。网络是一个层次结构,DNS 也是如此。.cn 这个顶级域可以提供其范围内域名的 DNS 服务;而小到一个公司、学校,它们也有自己的 DNS 服务器。
举个例子,.cn 的 DNS 服务器可以提供 example.cn、4399.cn、edu.cn 这样域名的 DNS 查询服务;而同济的 DNS 服务器可以提供 1.tongji.edu.cn、www.tongji.edu.cn 这样域名的 DNS 服务。是否注意到了层次结构?域名和英文的习惯是一样的,更大范围的标识符在后。
现在我们清楚了,输入一个域名,只有通过 DNS 服务转换为 IP 才能够访问。
之前,1 系统的服务器具有公网 IP,而且这个 IP 和 1.tongji.edu.cn 的对应关系也公开为人所知。现在的情况是,服务器的公网 IP 禁用了,或者学校的 DNS 服务器不再宣传 1.tongji.edu.cn 的 DNS 记录。
这就导致问题的出现,因为只有同济才知道 1.tongji.edu.cn 到底对应什么 IP,这是学校内部的结构,只有学校自己清楚。如果它不告诉外界,那外界就也不知道该如何访问到该域名对应的 IP 了。换言之,外网无法访问到 1 系统的服务。
你可能会想,既然它曾经公开过,一传十、十传百,那大家就知道这一对应关系。合理,但事实上,DNS 是有有效期的,过了有效期,曾经公开的记录便失效了。而消息源又不再宣传这一消息,久而久之,大家就都忘了某个 DNS 记录了。
所以,这串分析告诉我们,为什么外网会无法访问 1 系统的服务。因为不知道域名和 IP 的对应关系。
那,为什么内网可以呢?因为同济内网也有 DNS 服务器呀,当你在校园网环境下,不妨用 nslookup 看一下,默认的 DNS 服务器是同济自己的喔。而同济自己的 DNS 服务器会把 1.tongji.edu.cn 映射为一个内网 IP。这样在内网就能够访问 1 系统的服务了。
换言之,就算你在校园网可能访问不通外网,如百度、Github 这些网站,但内网的服务是可以访问的。这就好比你家宽带欠费了,访问不了百度,但不影响连接路由器的管理员界面(192.168.1.1)、打印机的 Web 接口,或者摄像头等内网设备。
ubuntu@VM-4-11-ubuntu:~$ MotionPro --help Usage: /opt/MotionPro/vpn_cmdline -s, --stop stop vpn -h, --host AG host (Required). If no port is given, the default port is 443. If referencing the shared virtual site, please add the alias name at the end. (i.e.hostname:port / alias) -u, --user username for login (Required) -p, --passwd password for login (Required) -k, --cookie connect to vpn with session cookie -m, --method aaa method for login; if there is only one method, this will choose the default method -c, --count Reconnect count, "inf" means reconnect all the time (Default: 0, means: no reconnect) -i, --interval interval between l3vpn reconnect attempts (Default: 0 sec, means: immediately; max: 3600 sec) -e, --enable enable proxy -t, --proxyhost Proxy host (Required if proxy enabled), if no port is given the default port is 0.(i.e. post:port) -n, --proxyuser Proxy username (Required if proxy enabled), if the user wants to assign a domain, please add the domain before the username. (i.e.domain\username) -w, --proxypwd Proxy password (Required if proxy enabled) -a, --status display vpn status -x, --validcode connect to vpn with session validcode -f, --certfile certificate file path for login (pfx format) -d, --certpass certificate file password -v, --capath ca path, to verify server cert -l, --loglevel log level: debug|info|warn|error -q, --quiet quiet mode -g, --syslog write log to syslog -b, --bandwidth download spped limit,upload speed limit(unit is kbps) -j, --pid browser pid -z, --break disconnect vpn but do not logout
一个很基本的想法是,把本机 IP 写入路由表,这样服务器就知道该通过原来的路径连接 PC,而不是走 VPN。理想很丰满,实际上,VPN 会覆盖路由表,导致写入的记录被覆盖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
default via 10.3.4.1 dev eth0 proto dhcp src 10.3.4.11 metric 100 10.3.4.0/22 dev eth0 proto kernel scope link src 10.3.4.11 metric 100 10.3.4.1 dev eth0 proto dhcp scope link src 10.3.4.11 metric 100 111.187.0.0/16 via 10.3.4.11 dev eth0 # 本机 IP,手动添加 183.60.82.98 via 10.3.4.1 dev eth0 proto dhcp src 10.3.4.11 metric 100 183.60.83.19 via 10.3.4.1 dev eth0 proto dhcp src 10.3.4.11 metric 100
# 启动 VPN 前(上)启动 VPN 后(下)
1.1.1.1 dev tun0 proto kernel scope link src 111.187.78.177 10.3.4.1 dev eth0 scope link 202.120.189.6 via 10.3.4.1 dev eth0 202.120.189.23 via 10.3.4.1 dev eth0 202.120.189.34 via 10.3.4.1 dev eth0
# 这是 /etc/resolve.conf nameserver 202.120.190.208 nameserver 202.120.190.108 # This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8). # Do not edit. # # This file might be symlinked as /etc/resolv.conf. If you're looking at # /etc/resolv.conf and seeing this text, you have followed the symlink. # # This is a dynamic resolv.conf file for connecting local clients to the # internal DNS stub resolver of systemd-resolved. This file lists all # configured search domains. # # Run "resolvectl status" to see details about the uplink DNS servers # currently in use. # # Third party programs should typically not access this file directly, but only # through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a # different way, replace this symlink by a static file or a different symlink. # # See man:systemd-resolved.service(8) for details about the supported modes of # operation for /etc/resolv.conf.
这里我确实不是做出很好的解释,但总而言之,需要在启用 VPN 的 DNS 服务后需要关闭 systemd-resolved。
将 DNS 服务器添加到路由表中
即使这样,还是不能解决问题。DNS 解析仍然出错。这次不是多个 DNS 冲突了,而是学校的 DNS 服务器连不上。考察路由表:
1 2 3 4 5 6 7 8 9 10
# 不完全正确的路由表 default via 10.3.4.1 dev eth0 1.1.1.1 dev tun0 proto kernel scope link src 111.187.82.242 10.0.0.0/8 dev tun0 scope link 10.3.4.1 dev eth0 scope link 172.16.0.0/12 dev tun0 scope link 192.168.0.0/16 dev tun0 scope link 202.120.189.6 via 10.3.4.1 dev eth0 202.120.189.23 via 10.3.4.1 dev eth0 202.120.189.34 via 10.3.4.1 dev eth0
学校 DNS 服务器并没有专属的一条记录,走默认网关 eth0,但问题是学校的 DNS 服务器可能设置了只接受内网请求。那,走公网的 eth0 是无法访问到的。需要添加如下记录:
1 2
202.120.190.108 dev tun0 scope link 202.120.190.208 dev tun0 scope link
你可能奇怪,为什么启用 VPN 就能找到 DNS 服务器呢?观察下表,启用 VPN 后,默认路由被删掉了。在这种条件下,一般来说,隐含的默认路由是 VPN,这样,发往 DNS 服务器的请求也走 VPN,一切正常。
1 2 3 4 5 6
# 启用 VPN 后的路由表 1.1.1.1 dev tun0 proto kernel scope link src 111.187.78.177 10.3.4.1 dev eth0 scope link 202.120.189.6 via 10.3.4.1 dev eth0 202.120.189.23 via 10.3.4.1 dev eth0 202.120.189.34 via 10.3.4.1 dev eth0
proc prompt_read {prompt} { # open the controlling tty for read/write set chan [open /dev/tty {RDWR}] # print prompt without newline puts -nonewline $chan$prompt flush $chan
# disable echo on the tty while reading (so typed code is not shown) exec sh -c {stty -echo < /dev/tty} gets $chan line exec sh -c {sttyecho < /dev/tty} puts $chan"" ;# newline after user typed (clean output) close $chan return$line }
VPN_DNS=$(resolvectl dns tun0 2>/dev/null | awk '{print $3}' | tr'\n'' ') if [ -z "$VPN_DNS" ]; then # 若获取失败则回退为同济默认 DNS VPN_DNS="202.120.190.208 202.120.190.108" fi
sudo unlink /etc/resolv.conf 2>/dev/null for dns in$VPN_DNS; do echo"nameserver $dns" | sudo tee -a /etc/resolv.conf >/dev/null done
echo"[INFO] DNS 修复完成,当前配置如下:" cat /etc/resolv.conf
# === Step 4. 打印路由表用于调试 === echo"[DEBUG] 当前路由表(VPN启动后):" ip route
# === Step 5. 恢复公网默认路由 === echo"[INFO] 恢复公网默认路由..." sudo ip route del default || true sudo ip route add default via $GW dev $IFACE
# === Step 6. 为校内常见网段添加路由到VPN === echo"[INFO] 添加内网路由到VPN(假设 VPN 接口为 tun0 或 ppp0)..." VPN_IFACE=$(ip link show | grep -E "tun|ppp" | awk -F: '{print $2}' | head -n 1 | tr -d ' ') if [ -z "$VPN_IFACE" ]; then echo"[WARN] 未检测到 VPN 接口,请检查 MotionPro 状态。" else sudo ip route add 10.0.0.0/8 dev $VPN_IFACE || true sudo ip route add 172.16.0.0/12 dev $VPN_IFACE || true sudo ip route add 192.168.0.0/16 dev $VPN_IFACE || true
# 把 VPN DNS IP 单独路由到 VPN 接口 for dns in$VPN_DNS; do sudo ip route add $dns/32 dev $VPN_IFACE || true done
echo"[INFO] 内网路由已配置到 $VPN_IFACE" echo"[INFO] VPN DNS 路由已添加" fi
# 2 停止 vpnd 后台服务(如果存在) if pgrep vpnd >/dev/null 2>&1; then echo"[INFO] 检测到 vpnd 正在运行,尝试停止..." sudo pkill vpnd && echo"[OK] vpnd 已停止。" else echo"[INFO] vpnd 未运行。" fi
# 3 恢复默认系统 DNS 设置 echo"[INFO] 恢复系统默认 DNS 配置..." sudo rm -f /etc/resolv.conf sudo ln -s /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf sudo systemctl restart systemd-resolved echo"[OK] DNS 已恢复为 systemd-resolved 管理模式。"
# 4 删除 VPN 残留路由(可选) # tun0 / ppp0 都可能是 VPN 设备,逐一清理 for dev in tun0 ppp0; do if ip link show $dev >/dev/null 2>&1; then echo"[INFO] 删除 VPN 设备相关路由 ($dev)..." sudo ip route flush dev $dev sudo ip linkset$dev down fi done
# 5 检查网络是否恢复 echo"[INFO] 检查网络连通性..." if ping -c 1 -W 2 8.8.8.8 >/dev/null 2>&1; then echo"[SUCCESS] 网络恢复正常。" else echo"[ERROR] 网络仍不可达,请检查默认网关或 DHCP。" fi