惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
The Exploit Database - CXSecurity.com
J
Java Code Geeks
H
Help Net Security
B
Blog RSS Feed
G
Google Developers Blog
博客园 - 司徒正美
MongoDB | Blog
MongoDB | Blog
量子位
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog
P
Proofpoint News Feed
小众软件
小众软件
人人都是产品经理
人人都是产品经理
云风的 BLOG
云风的 BLOG
V
V2EX
月光博客
月光博客
C
Check Point Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
A
Arctic Wolf
Help Net Security
Help Net Security
Schneier on Security
Schneier on Security
D
DataBreaches.Net
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Palo Alto Networks Blog
T
Tenable Blog
L
LangChain Blog
Attack and Defense Labs
Attack and Defense Labs
Google DeepMind News
Google DeepMind News
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
F
Fortinet All Blogs
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
大猫的无限游戏
大猫的无限游戏
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Y
Y Combinator Blog
WordPress大学
WordPress大学
Stack Overflow Blog
Stack Overflow Blog
V
Visual Studio Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
NISL@THU
NISL@THU
GbyAI
GbyAI
博客园 - Franky
S
Secure Thoughts
有赞技术团队
有赞技术团队
PCI Perspectives
PCI Perspectives
U
Unit 42

折腾不停 – 魔帆博客

Python包管理的血泪史:从混乱到秩序的漫长征 | 魔帆博客 配置和使用 Windows Dev Drive 开发驱动器 | 魔帆博客 解锁iOS侧载自由:使用sideStore轻松搞定ipa签名 | 魔帆博客 Git配置:如何优雅的配置多用户并使用 ssh 密钥验证 | 魔帆博客 Fedora 系统升级 32->34 跨版本升级 | 魔帆博客 教程:如何更新安装 docker-compose V2 和使用 docker switch | 魔帆博客 Windows10 系统盘开启 Bitlocker | 魔帆博客 2022 年 Android 下的安卓浏览器使用指北-Firefox向 | 魔帆博客 Docker WSL1/2 迁移 Linux 发行版目录 | 魔帆博客 Spotify 主题 spicetify-fluent - 微软 win11 风格美化 | 魔帆博客 双重验证 Authy 导出所有 TOTP token 和 golang 配置 GOPROXY 解决网络问题 | 魔帆博客 powershll 像 bash 一样为单个命令设置临时环境变量 | 魔帆博客 Linux 教程:Linux 初学者必了解的概念 | 魔帆博客 安卓电池充电保护-智能充电/温控切断(Root方案) | 魔帆博客 备用机养成方案 - Tasker 安卓短信转发到 telegram | 魔帆博客 VS Code C/C++ 环境配置 | 魔帆博客 创建支持安全启动(Secure Boot)的 Arch Linux ISO 安装镜像 | 魔帆博客 使用 Aria2 搭建离线下载服务器 | 魔帆博客 微信小程序健康打卡自动填报程序-使用 Fiddler 抓包 | 魔帆博客
使用 GNU/Linux 搭建多出口软路由 | 魔帆博客
chenjunyu19 · 2024-05-24 · via 折腾不停 – 魔帆博客

简介

这篇文章记录了使用 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 和私网 IP 192.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.servicesmartdns.service

SNAT 配置

私网到私网

lab network rules 1

虽然这种情况一般不会发生,但此处还是进行了考虑。对于这种数据包,可以选择原样转发或者丢弃,此处选择进行原样转发。

外部到私网

lab network rules 2

对于同一个二层网络内的校园网 IP 设备,如有特殊需求,是可以将 192.168.0.0/24 路由到 172.16.0.1(软路由)实现访问的。针对这种需求,我们可以将目的地址为私网的数据包通过 SNAT 改写源地址为 192.168.0.1(软路由)。这不是必须的,但我感觉这样做会好一点。

私网到校园网

lab network rules 3

访问校园网内的设备没有额外的带宽限制,所以我们希望对外表现出的 IP 是稳定的。这里使用 RFC 1918 定义的“专用网络”地址段来覆盖校园网。

校园网到校园网

lab network rules 4

正如前面所说的,由于软路由也具有校园网 IP,同一个二层网络内的设备也是可以将软路由作为默认网关的。由于其本身就已经具有校园网 IP,所以没有必要进行一次额外的 SNAT,对这些数据包原样转发。

互联网

lab network rules 5

在经过前面四组规则的处理后,我们认为剩余的未匹配数据包都属于互联网流量,需要进行多出口 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