LabHub
学习 学习路径 课程

网络基础 — 在 Linux 虚拟机里动手

带路由器、DNS、防火墙和 NAT 的小网络

在 LabHub 中继续学习

本实验在 VM 中运行

本实验将前九个实验整合在一起。在命名空间 home(用户侧)与 dmz(服务器侧) 之间,由 VM 自身充当路由器,并由该路由器兼任 DNS 服务器、防火墙和 NAT。 这相当于一台家用路由器所做工作的缩小版。实验时限为 60 分钟,因此可能需要 延长一次时间——请注意,成果会随 VM 一同消失。

目标

连接两个子网,让客户端能按名称找到服务器,只允许 Web 流量通过,使私有网络 能够访问互联网,用数据包验证这一切,最后形成报告。

为什么重要

此前每次只观察一个层次。真实故障往往跨越多个层次——名称能够解析,但被防火墙 拦截;防火墙已经放行,却没有返回路径。亲手从头到尾搭建过一个网络的人,在听到 “无法访问”时会有明确的排查顺序:链路 → 地址 → 邻居 → 路由 → 名称 → 端口 → 防火墙 → 响应。

步骤

  1. 创建命名空间 homedmz,以及 veth home0(home,10.40.1.10/24)↔r-home(根命名空间,10.40.1.1/24)、dmz0(dmz,10.40.2.10/24)↔r-dmz(根命名空间,10.40.2.1/24)。配置两个命名空间的默认路由和根命名空间的 ip_forward,使 homedmz 能够 ping 通。
  2. 创建 /root/final/www/index.html,在 dmz 中启动监听 10.40.2.10:80 的 Web 服务器(日志写入 /root/final/http.log),使 home 中能够执行 curl http://10.40.2.10/
  3. 通过 /etc/dnsmasq.d/lab.conf 让 dnsmasq 监听 10.40.1.1,对 web.lab.internal10.40.2.10 作出应答,并将其余查询转发给上游;再通过 /etc/netns/home/resolv.confhome 使用该服务器。
  4. home 中执行 curl -si http://web.lab.internal/,将响应保存到 /root/final/byname.txt
  5. 在根命名空间中创建表 inet labfw 和带 forward 钩子的链(策略为 drop),只允许 established,related 以及 homedmztcp dport 80,使 Web 可以访问而 ping 无法通过。
  6. 在表 ip labnat 中为 10.40.1.0/24 添加伪装,并在 forward 中允许 home→uplink 的 tcp dport { 80, 443 }。从 home 执行 curl -sI http://archive.ubuntu.com/,将第一行保存到 /root/final/internet.txt
  7. r-dmz 上进行抓包,同时从 home 再次访问 Web;将能够看到 10.40.1.1010.40.2.10.80 发送 SYN 的输出保存到 /root/final/capture.txt
  8. 将完整规则保存到 /root/final/ruleset.nft,并在 /root/final/report.md 中写入 home_ip=dmz_ip=dns=ping_blocked= 四行,以及收到“web.lab.internal 无法打开”的报告时应按什么顺序排查。

参考

两个子网与路由器

创建命名空间 homedmz,以及 veth home0(home,10.40.1.10/24)↔r-home(根命名空间,10.40.1.1/24)、dmz0(dmz,10.40.2.10/24)↔r-dmz(根命名空间,10.40.2.1/24)。配置两个命名空间的默认路由和根命名空间的 ip_forward,使 homedmz 能够 ping 通。

将第 8 个实验的第 1 步执行两遍。veth 的 r- 侧保留在根命名空间中。ip -n home route add default via 10.40.1.1ip -n dmz route add default via 10.40.2.1sysctl -w net.ipv4.ip_forward=1

DMZ 中的 Web 服务器

创建 /root/final/www/index.html,在 dmz 中启动监听 10.40.2.10:80 的 Web 服务器(日志写入 /root/final/http.log),使 home 中能够执行 curl http://10.40.2.10/

ip netns exec dmz setsid python3 -m http.server 80 --bind 10.40.2.10 --directory /root/final/www > /root/final/http.log 2>&1 < /dev/null &。在 index.html 中加入单词 dmz,以后会更容易区分响应。

让路由器兼任 DNS

通过 /etc/dnsmasq.d/lab.conf 让 dnsmasq 监听 10.40.1.1,对 web.lab.internal10.40.2.10 作出应答,并将其余查询转发给上游;再通过 /etc/netns/home/resolv.confhome 使用该服务器。

在第 4 个实验的配置中加入 server=<상류>,并保留 no-resolv(表示不要从 resolv.conf 读取上游,而要从这一行读取)。执行 systemctl restart dnsmasq。在 /etc/netns/home/resolv.conf 中写入 nameserver 10.40.1.1。验证:ip netns exec home getent hosts web.lab.internal

按名称访问

home 中执行 curl -si http://web.lab.internal/,将响应保存到 /root/final/byname.txt

ip netns exec home curl -si -m 3 http://web.lab.internal/ > /root/final/byname.txt-i 会连同响应头一起输出。应当能看到 200 OK 和 index.html 的内容。

只允许 Web 流量通过

在根命名空间中创建表 inet labfw 和带 forward 钩子的链(策略为 drop),只允许 established,related 以及 homedmztcp dport 80,使 Web 可以访问而 ping 无法通过。

nft add table inet labfw; nft 'add chain inet labfw forward { type filter hook forward priority 0; policy drop; }'。添加两条规则:ct state established,related acceptiifname "r-home" oifname "r-dmz" tcp dport 80 accept。此时 home 中的 ping 应超时,而 curl 应返回 200。

让家庭网络访问互联网

在表 ip labnat 中为 10.40.1.0/24 添加伪装,并在 forward 中允许 home→uplink 的 tcp dport { 80, 443 }。从 home 执行 curl -sI http://archive.ubuntu.com/,将第一行保存到 /root/final/internet.txt

直接采用第 8 个实验的第 3 步(ip saddr 10.40.1.0/24 oifname "enp1s0" counter masquerade)。然后在 forward 中添加 iifname "r-home" oifname "enp1s0" tcp dport { 80, 443 } accept。DNS 由路由器自身(dnsmasq)应答,因此不会经过 forward。

使用数据包验证

r-dmz 上进行抓包,同时从 home 再次访问 Web;将能够看到 10.40.1.1010.40.2.10.80 发送 SYN 的输出保存到 /root/final/capture.txt

先执行 timeout 5 tcpdump -i r-dmz -nn -l 'tcp port 80' > /root/final/capture.txt 2>&1 &,再执行 ip netns exec home curl -s http://web.lab.internal/。输出中必须有 10.40.1.10.<포트> > 10.40.2.10.80: Flags [S] 这一行。注意源地址保持不变——内部网络之间没有 NAT。

规则与报告

将完整规则保存到 /root/final/ruleset.nft,并在 /root/final/report.md 中写入 home_ip=dmz_ip=dns=ping_blocked= 四行,以及收到“web.lab.internal 无法打开”的报告时应按什么顺序排查。

nft list ruleset > /root/final/ruleset.nft。报告中的四个值依次为 10.40.1.10、10.40.2.10、10.40.1.1、yes。排查顺序必须包含名称(getent)、路由(ip route get)、防火墙(nft counter)和端口(ss)。