Network Fundamentals — Hands-on in a Linux VM
A Small Network with Router, DNS, Firewall and NAT
This lab runs on a VM
You bring the previous nine labs together into one. Between the namespaces home (the user side) and dmz (the server side),
the VM itself stands as the router, and that router also takes on the DNS server, the firewall, and
NAT. It is a scaled-down version of what one home router does. It is a 60-minute lab, so you may need to extend the time
once — your work disappears together with the VM, so be aware of that in advance.
Goal
Connect two subnets, let clients find the server by name, let only the web through, send the private network out to the internet, confirm all of it with packets, and then leave a report.
Why it matters
Until now you looked at one layer at a time. Real outages have several layers overlapping — the name resolves but the firewall blocks, the firewall is open but there is no return path. Someone who has built a network from start to finish has an order in which to look when they hear "it doesn't work": link → address → neighbor → route → name → port → firewall → response.
Steps
- Create the namespaces
home·dmzand the vethshome0(in home,10.40.1.10/24)↔r-home(in root,10.40.1.1/24) anddmz0(in dmz,10.40.2.10/24)↔r-dmz(in root,10.40.2.1/24), and set the default routes of the two namespaces andip_forwardin root so that ping works fromhometodmz. - Create
/root/final/www/index.html, start a web server listening on10.40.2.10:80insidedmz(log to/root/final/http.log), and makecurl http://10.40.2.10/work fromhome. - With
/etc/dnsmasq.d/lab.conf, make dnsmasq listen on10.40.1.1, answerweb.lab.internal→10.40.2.10, and pass everything else upstream, and with/etc/netns/home/resolv.conf, makehomeuse that server. - Save the response to
curl -si http://web.lab.internal/fromhometo/root/final/byname.txt. - In root, create a table
inet labfwand aforwardhook chain (policydrop), and allow onlyestablished,relatedandtcp dport 80fromhometodmz, so that the web works and ping does not. - Put masquerade for
10.40.1.0/24in the tableip labnat, allowtcp dport { 80, 443 }fromhometo the uplink inforward, and save the first line ofcurl -sI http://archive.ubuntu.com/fromhometo/root/final/internet.txt. - Capture on
r-dmzwhile fetching the web once more fromhome, and save the output showing the SYN that10.40.1.10sent to10.40.2.10.80to/root/final/capture.txt. - Save the complete ruleset to
/root/final/ruleset.nft, and in/root/final/report.mdwrite four lines,home_ip=·dmz_ip=·dns=·ping_blocked=, together with the order in which you would look when you receive the report "web.lab.internal won't open".
Notes
- You combine the commands from the earlier labs as they are. The hints from labs 3 and 8 are especially useful.
- To make dnsmasq pass queries upstream, write
server=<상류주소>together withno-resolv(the placeholder is the upstream address). The upstream comes fromresolvectl dns enp1s0. - The firewall goes in the forward chain. Do not touch the VM's own input — it would block the grading agent.
nft add rule inet labfw forward iifname "r-home" oifname "r-dmz" tcp dport 80 accept.- A common mistake: leaving out the uplink-side allowance in forward in step 6. A NAT rule alone cannot get past the drop in forward.
Two subnets and a router
Create the namespaces home·dmz and the veths home0 (in home, 10.40.1.10/24)↔r-home (in root, 10.40.1.1/24) and dmz0 (in dmz, 10.40.2.10/24)↔r-dmz (in root, 10.40.2.1/24), and set the default routes of the two namespaces and ip_forward in root so that ping works from home to dmz.
Step 1 of lab 8, twice. The r- end of each veth stays in root. ip -n home route add default via 10.40.1.1, ip -n dmz route add default via 10.40.2.1, sysctl -w net.ipv4.ip_forward=1.
The web server in the DMZ
Create /root/final/www/index.html, start a web server listening on 10.40.2.10:80 inside dmz (log to /root/final/http.log), and make curl http://10.40.2.10/ work from home.
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 &. If you put the word dmz in index.html, it is easier to tell the responses apart later.
The router takes on DNS too
With /etc/dnsmasq.d/lab.conf, make dnsmasq listen on 10.40.1.1, answer web.lab.internal→10.40.2.10, and pass everything else upstream, and with /etc/netns/home/resolv.conf, make home use that server.
Add server=<상류> to the configuration from lab 4 (the placeholder is the upstream address) and keep no-resolv as it is (it means read the upstream from this line, not from resolv.conf). systemctl restart dnsmasq. Put nameserver 10.40.1.1 in /etc/netns/home/resolv.conf. To check: ip netns exec home getent hosts web.lab.internal.
Open it by name
Save the response to curl -si http://web.lab.internal/ from home to /root/final/byname.txt.
ip netns exec home curl -si -m 3 http://web.lab.internal/ > /root/final/byname.txt. -i prints the headers too. 200 OK and the contents of index.html must be visible.
Only the web gets through
In root, create a table inet labfw and a forward hook chain (policy drop), and allow only established,related and tcp dport 80 from home to dmz, so that the web works and ping does not.
nft add table inet labfw; nft 'add chain inet labfw forward { type filter hook forward priority 0; policy drop; }'. Two rules: ct state established,related accept and iifname "r-home" oifname "r-dmz" tcp dport 80 accept. Now ping from home must time out and curl must return 200.
From inside the house to the internet
Put masquerade for 10.40.1.0/24 in the table ip labnat, allow tcp dport { 80, 443 } from home to the uplink in forward, and save the first line of curl -sI http://archive.ubuntu.com/ from home to /root/final/internet.txt.
Exactly step 3 of lab 8 (ip saddr 10.40.1.0/24 oifname "enp1s0" counter masquerade). Then, in forward, iifname "r-home" oifname "enp1s0" tcp dport { 80, 443 } accept. DNS is answered by the router itself (dnsmasq), so it does not pass through forward.
Confirm with packets
Capture on r-dmz while fetching the web once more from home, and save the output showing the SYN that 10.40.1.10 sent to 10.40.2.10.80 to /root/final/capture.txt.
After timeout 5 tcpdump -i r-dmz -nn -l 'tcp port 80' > /root/final/capture.txt 2>&1 &, run ip netns exec home curl -s http://web.lab.internal/. There must be a 10.40.1.10.<포트> > 10.40.2.10.80: Flags [S] line (the port placeholder is the client's port). Notice that the source is unchanged — there is no NAT between the two inner networks.
Rules and report
Save the complete ruleset to /root/final/ruleset.nft, and in /root/final/report.md write four lines, home_ip=·dmz_ip=·dns=·ping_blocked=, together with the order in which you would look when you receive the report "web.lab.internal won't open".
nft list ruleset > /root/final/ruleset.nft. The four values in the report are 10.40.1.10, 10.40.2.10, 10.40.1.1, and yes. The order must include name (getent), route (ip route get), firewall (nft counter), and port (ss).