Messing around with network namespaces
I haven’t worked with namespaces yet so today I’m going to try some experiments to try to familiarize myself with network interfaces.
Namespaces
I’m going to first make a namespace called ns1
:
sudo ip netns add ns1
Running commands within a network namespace goes like this:
sudo ip netns exec ns1 <command>
If I run bash
as the command, and run nc -l 8900
in the namespace, netstat
shows that the server exists.
$ sudo ip netns exec ns1 bash
root@jaehee:/home/jaehee# netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8900 0.0.0.0:* LISTEN
It’s listening on 0.0.0.0:8900
which means it’s listening all network interfaces. But since I haven’t set up any interfaces yet, when I curl
, no packets would be detected. And that is inline with what I see:
root@jaehee:/home/jaehee# curl localhost:8900
curl: (7) Couldn't connect to server
But if I setup a loopback lo
interface, curl
should send packets this time. and nc
should receive them.
Let’s setup the loopback interface (in the namespace)
ip link set dev lo up
Now let’s try curl localhost:8900
from another instance of the namespace and we should see a packet show up. And it does!
root@jaehee:/home/jaehee# ip link set dev lo up
root@jaehee:/home/jaehee# nc -l 8900
GET / HTTP/1.1
Host: localhost:8900
User-Agent: curl/7.68.0
Accept: */*
So, when we add a network interface, the server starts on 0.0.0.0
.
Routing
We have interfaces/devices that want to send data to eachother. And there are paths or routes connecting these interfaces where traffic flows. The packets of data are assigned a network device.
Step 1 iptables has prerouting rules
iptables lets you create rules to match network packets and accept/drop/modify them. It’s used for firewalls and NAT. Every iptable rule has a target (what to do with the matching packets. e.g. accept/drop/modify). The iptables have chains, and chains have rules. There are tables for filter, nat, etc. The chains in the table has input, forward, prerouting options. And the rules are what looks like -s 172.17.0.0 -j DROP
Step 2 The packets get routed
You can see the routes on the route table. On my computer, I have a few interfaces. When I run ifconfig
I can see a list of my interfaces. I have docker
, lo
, enp
, wlp
, wg
, virbr
, etc. And if I run sudo ip route list table all
I can see my routes.
$ sudo ip route list table all
default via 192.168.0.1 dev wlp0s20f3 proto dhcp metric 600
169.254.0.0/16 dev virbr0 scope link metric 1000 linkdown
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.64.2.0/24 dev wg0 scope link
192.168.0.0/24 dev wlp0s20f3 proto kernel scope link src 192.168.0.31 metric 600
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown
broadcast 127.0.0.0 dev lo table local proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1
broadcast 172.17.0.0 dev docker0 table local proto kernel scope link src 172.17.0.1 linkdown
local 172.17.0.1 dev docker0 table local proto kernel scope host src 172.17.0.1
... etc ...
On the last line it says local
in the front, so the packets sent to 172.17.0.1
goes to local
.
Step 3 tcpdump gets the packet
Once there is a network interface associated with the packet, the packet gets sent there and we can observe that the packet gets sent with tcpdump.
Summary
Before routing, there is a prerouting chain in the iptables that happens. When you send a packet to an IP address, the route table decides which network interface the packet goes through. For the packets to go through the Linux kernel network stack, you need network interfaces. Once routed thorugh an interface, you can use tcpdump to capture packets.