简介
这篇文章记录了使用 GNU/Linux 操作系统,在不更改二层网络配置的前提下,扩展实验室网络环境,并在一定程度上改善网络使用体验的方法。
背景
假设学校网络与信息中心给我们分配了一个校园网 VLAN,对应的校园网 IPv4 地址段为 172.16.0.0/26
。按照常规用法,我们需要手动给网络下的每一台设备配置位于 172.16.0.1
~ 172.16.0.61
之间的 IPv4 地址,并将 172.16.0.62
设为默认网关。连接到这个网络下的设备包括但不限于:若干台业务服务器、实验室成员的有线上网设备、通过实验室 Wi-Fi 无线上网的设备。按照这样的方法使用,有以下问题。
- 网络内没有 DHCP 服务器,手动分配、管理和配置每台设备的 IP 地址较为不便。
- 这些校园网 IP 地址在全校范围内可路由,相当于设备会直接暴露在整个校园网中,对开放了 SSH、Windows 远程桌面等远程访问的设备存在安全威胁。
- 手机、平板等普通上网需求设备一般没有必要取得校园网 IP 地址,给他们分配校园网 IP 地址存在资源浪费和管理困难问题。
- 实验室 Wi-Fi 由一台家用路由器提供,它工作在路由模式,只享有 1 个校园网 IP 地址,其下属的所有设备共享这一个 IP 的校园网出口带宽。
设计
针对上面提到的问题,我想到了以下解决方案。
- 在同一个二层网络内,规划
192.168.0.0/24
为我们的私有 IP 地址段,用于满足普通联网需求,通过 NAT 访问校园网和互联网。这段地址在校园网中不会被路由到我们这里,因此在校园网的其他位置无法直接访问位于此段中的设备。 - 将无线路由器调整为 AP 模式,不再进行 NAT。无线接入的设备与有线接入的设备具有同等性质。
- 在网络中接入一台 GNU/Linux 主机,承担 DHCP 服务器、DNS 服务器和 NAT 网关的角色,具有校园网 IP
172.16.0.1
和私网 IP192.168.0.1
。 - NAT 网关将私网设备的出网流量按照轮询调度(Round-Robin)的方式 SNAT 到
172.16.0.1
~172.16.0.16
共 16 个校园 IP 地址,避免私网设备同时用网时出口带宽受限。
实现
服务配置
首先,准备一个接入到实验室网络的 GNU/Linux 系统。在此处,我选择了自己熟悉的 Arch Linux 系统,使用 systemd-networkd
作为网络管理器,使用 SmartDNS 作为 DNS 服务器。
根据前面的设计,配置好系统的网络信息。systemd-networkd
同时也可承担 DHCP 服务器的角色,如果没有特殊需求的话可以选择使用,免去了额外安装配置其他 DHCP 服务器软件的麻烦。配置文件参考如下。
[Match]
# 匹配网络接口名称
Name=eno1
[Network]
# 开启 DHCP 服务器
DHCPServer=true
# 校园网网关
Gateway=172.16.0.62
# 校园网 IP
Address=172.16.0.1/26
Address=172.16.0.2/26
Address=172.16.0.3/26
Address=172.16.0.4/26
Address=172.16.0.5/26
Address=172.16.0.6/26
Address=172.16.0.7/26
Address=172.16.0.8/26
Address=172.16.0.9/26
Address=172.16.0.10/26
Address=172.16.0.11/26
Address=172.16.0.12/26
Address=172.16.0.13/26
Address=172.16.0.14/26
Address=172.16.0.15/26
Address=172.16.0.16/26
# 私网 IP
Address=192.168.0.1/24
[DHCPServer]
# DHCP 服务器地址
ServerAddress=192.168.0.1/24
# 向下游设备派发 DNS 服务器地址为(DHCP 服务器地址)本机
DNS=_server_address
由于学校提供的 DNS 服务质量不佳(存在 DNS 劫持和污染现象),我选择手动搭建一个 DNS 服务器,针对学校域名使用学校 DNS 解析,其他域名使用公共 DNS 解析。
server x.x.x.x -group campus -bootstrap-dns
server y.y.y.y -group campus -bootstrap-dns
server-tls dns.alidns.com
server-tls dot.pub
server-https https://cloudflare-dns.com/dns-query
server-https https://dns.quad9.net/dns-query
response-mode fastest-ip
nameserver /xxx.edu.cn/campus
force-qtype-SOA 65
prefetch-domain yes
完成配置文件的编写后,激活并启动 systemd-networkd.service
和 smartdns.service
。
SNAT 配置
私网到私网
虽然这种情况一般不会发生,但此处还是进行了考虑。对于这种数据包,可以选择原样转发或者丢弃,此处选择进行原样转发。
外部到私网
对于同一个二层网络内的校园网 IP 设备,如有特殊需求,是可以将 192.168.0.0/24
路由到 172.16.0.1
(软路由)实现访问的。针对这种需求,我们可以将目的地址为私网的数据包通过 SNAT 改写源地址为 192.168.0.1
(软路由)。这不是必须的,但我感觉这样做会好一点。
私网到校园网
访问校园网内的设备没有额外的带宽限制,所以我们希望对外表现出的 IP 是稳定的。这里使用 RFC 1918 定义的“专用网络”地址段来覆盖校园网。
校园网到校园网
正如前面所说的,由于软路由也具有校园网 IP,同一个二层网络内的设备也是可以将软路由作为默认网关的。由于其本身就已经具有校园网 IP,所以没有必要进行一次额外的 SNAT,对这些数据包原样转发。
互联网
在经过前面四组规则的处理后,我们认为剩余的未匹配数据包都属于互联网流量,需要进行多出口 SNAT 处理。这里参考的是《私有实例轮询使用多公网 IP 访问公网的实现方案 | 亚马逊AWS官方博客》,在此对有关作者表示感谢。
综合
最后,将这些规则持久化到一个文件中,并在系统每次启动时自动加载。根据发行版,文件路径、服务名称和软件包名称会有所不同。在 Arch Linux 中,可以将规则写入到 /etc/iptables/iptables.rules
中,然后激活并启动 iptables.service
。
warning 请注意
如果你的系统上还运行着其他防火墙软件,请不要使用上面给出的方法。你应该将这些规则写入到你正在使用的防火墙配置中。
*nat
# Private -> Private
-A POSTROUTING -s 192.168.0.0/24 -d 192.168.0.0/24 -j RETURN
# Others -> Private
-A POSTROUTING -d 192.168.0.0/24 -j SNAT --to-source 192.168.0.1
# Private -> Site
-A POSTROUTING -s 192.168.0.0/24 -d 10.0.0.0/8 -j SNAT --to-source 172.16.0.1
-A POSTROUTING -s 192.168.0.0/24 -d 172.16.0.0/12 -j SNAT --to-source 172.16.0.1
-A POSTROUTING -s 192.168.0.0/24 -d 192.168.0.0/16 -j SNAT --to-source 172.16.0.1
# Others -> Site
-A POSTROUTING -d 10.0.0.0/8 -j RETURN
-A POSTROUTING -d 172.16.0.0/12 -j RETURN
-A POSTROUTING -d 192.168.0.0/16 -j RETURN
# Internet
-A POSTROUTING -m statistic --mode nth --every 16 --packet 0 -j SNAT --to-source 172.16.0.16
-A POSTROUTING -m statistic --mode nth --every 15 --packet 0 -j SNAT --to-source 172.16.0.15
-A POSTROUTING -m statistic --mode nth --every 14 --packet 0 -j SNAT --to-source 172.16.0.14
-A POSTROUTING -m statistic --mode nth --every 13 --packet 0 -j SNAT --to-source 172.16.0.13
-A POSTROUTING -m statistic --mode nth --every 12 --packet 0 -j SNAT --to-source 172.16.0.12
-A POSTROUTING -m statistic --mode nth --every 11 --packet 0 -j SNAT --to-source 172.16.0.11
-A POSTROUTING -m statistic --mode nth --every 10 --packet 0 -j SNAT --to-source 172.16.0.10
-A POSTROUTING -m statistic --mode nth --every 9 --packet 0 -j SNAT --to-source 172.16.0.9
-A POSTROUTING -m statistic --mode nth --every 8 --packet 0 -j SNAT --to-source 172.16.0.8
-A POSTROUTING -m statistic --mode nth --every 7 --packet 0 -j SNAT --to-source 172.16.0.7
-A POSTROUTING -m statistic --mode nth --every 6 --packet 0 -j SNAT --to-source 172.16.0.6
-A POSTROUTING -m statistic --mode nth --every 5 --packet 0 -j SNAT --to-source 172.16.0.5
-A POSTROUTING -m statistic --mode nth --every 4 --packet 0 -j SNAT --to-source 172.16.0.4
-A POSTROUTING -m statistic --mode nth --every 3 --packet 0 -j SNAT --to-source 172.16.0.3
-A POSTROUTING -m statistic --mode nth --every 2 --packet 0 -j SNAT --to-source 172.16.0.2
-A POSTROUTING -m statistic --mode nth --every 1 --packet 0 -j SNAT --to-source 172.16.0.1
COMMIT
开启 IP 转发
最后,别忘了在内核中开启 IPv4 转发。你可能还会想要配置额外的防火墙规则来保护软路由本身的安全。
net.ipv4.ip_forward = 1
net.ipv4.conf.all.forwarding = 1
发表回复