Build a TCP/IP Stack from Scratch · Module 02

Concept: How a TAP Interface Works

Concept: How a TAP Interface Works

Let's start by understanding how we're going to "see" network traffic from our program.

You might think you'd need special hardware or kernel access to read Ethernet frames — but Linux gives us a neat trick for that: TUN/TAP devices.

TUN vs TAP — what's the difference?

  • TUN stands for network TUNnel. It handles Layer 3 (IP) packets — no Ethernet headers, just raw IP datagrams.
  • TAP stands for network TAP (as in wire tap). It handles Layer 2 (Ethernet) frames — exactly what we need, since we want to build our own network stack from the ground up.

When you create a TAP device, Linux treats it like a normal network interface (it even shows up in ip addr).

But instead of connecting to a physical NIC, the packets go straight into your program via a simple file descriptor — you just read() and write() like it's a normal file.

The mental picture

Here's what happens when you use a TAP device inside your stack container:

+--------------------------------------------+
| Your Program |
|--------------------------------------------|
| read(fd) → Ethernet frame from the kernel |
| write(fd) → Ethernet frame to the kernel |
+--------------------------------------------+
 ↑
 │ (virtual wire)
 ↓
 +------------------+
 | tap0 interface |
 +------------------+
 ↑
 │
 Docker bridge + client container

It's like your program is pretending to be a real network card.

Every frame sent to tap0 by another container (like the client) pops out of your program's file descriptor.

When your program writes bytes back, they re-enter the network as if they came from hardware.

Why we use TAP here

We use TAP instead of a real NIC for three main reasons:

  1. Safety: it's all virtual — no risk of breaking your host's real network.
  2. Visibility: we can print, log, and manipulate every byte that passes through.
  3. Control: you decide how to respond — you can be a router, a host, or even drop packets for fun.

In the next section, you'll modify your container so your program can open /dev/net/tun and create this virtual Ethernet interface, the gateway to your own network stack.