The Architecture of the Internet#

The TCP/IP Model is the framework that describes how data is packaged, addressed, transmitted, routed, and received on a network. It is the practical counterpart to the theoretical 7-layer OSI model: four layers that map closely onto how operating systems and network devices are actually built. When something breaks, the model tells you which layer to test first and which tool to reach for.

The 4 Layers of TCP/IP#

  1. Application Layer Where your software lives. It defines the messages programs exchange and what they mean. - Protocols: HTTP (web), SMTP (email), DNS (name resolution), SSH (remote access), TLS (usually drawn here, see below). - Data unit: message / data. - Example: Your browser writes GET / HTTP/1.1 plus headers.

  2. Transport Layer End-to-end communication between two processes. It adds ports (so many programs can share one IP), and, for TCP, reliability, ordering, flow control and congestion control. - Protocols: TCP (reliable stream), UDP (independent datagrams), QUIC (reliable streams built on UDP). - Data unit: segment (TCP) or datagram (UDP). - Example: The OS attaches a source port (e.g. 54321, chosen from the ephemeral range) and a destination port (443 for HTTPS).

  3. Internet Layer Logical addressing and routing across many interconnected networks. Every router along the path works at this layer. - Protocols: IPv4, IPv6, ICMP (ping, "destination unreachable", "time exceeded"). - Data unit: packet. - Example: A router reads the destination IP, looks it up in its routing table, decrements the TTL, and forwards the packet to the next hop.

  4. Link Layer (Network Access) Moves frames across one physical or logical link: a cable, a Wi-Fi association, a virtual NIC. - Protocols: Ethernet, Wi-Fi (802.11), ARP (which glues IPv4 to MAC addresses). - Data unit: frame. - Example: The packet is wrapped in an Ethernet frame addressed to the MAC of your default gateway, not the final server. See Ethernet, ARP & Switching for how that MAC is found.

Numbering conventions vary. Many engineers keep the OSI numbers even when talking about TCP/IP, which is why "Layer 4 load balancer" means transport and "Layer 7" means application. Use the names when in doubt.

Encapsulation#

When you send data, it travels down the stack. The application produces a message; the transport layer prepends a TCP header; the internet layer prepends an IP header; the link layer prepends an Ethernet header (and appends a checksum trailer). This is encapsulation. The receiver travels up the stack, stripping one header per layer until the original bytes reach the application.

Each layer only reads its own header. A switch reads the Ethernet header, a router reads the IP header, and only the destination host reads the TCP header and payload. That separation is why you can swap Ethernet for Wi-Fi or 5G without touching your browser.

The headers also cost bytes. On a standard Ethernet link the MTU (the largest IP packet the link carries) is 1500 bytes:

Piece Bytes Notes
Ethernet header 14 dst MAC, src MAC, EtherType
IPv4 header 20 without options (IPv6: 40)
TCP header 20 without options; commonly 32 with timestamps
TCP payload (MSS) 1460 1500 - 20 - 20
Ethernet FCS trailer 4 CRC checksum, not counted in MTU

This arithmetic explains real bugs. A VPN or overlay tunnel adds its own headers, so the inner packet must be smaller. If something along the path drops the ICMP "fragmentation needed" messages, large packets silently vanish while small ones work: SSH connects, but git clone hangs. That symptom is almost always an MTU problem, not an application bug.

Peeling a Real Frame in Python#

Here is an Ethernet frame carrying an HTTP request, as raw hex. The script decapsulates it layer by layer using only the standard library:

import struct, ipaddress

frame = bytes.fromhex(
    "00112233445566778899aabb0800"                      # Ethernet header
    "4500004d1c4640004006209ec0a80114cb00710a"          # IPv4 header
    "d4310050000003e800001389501801f600000000"          # TCP header
    "474554202f20485454502f312e310d0a486f73743a206578"  # payload...
    "616d706c652e636f6d0d0a0d0a"
)

# Link layer: 6-byte dst MAC, 6-byte src MAC, 2-byte EtherType
dst, src, ethertype = struct.unpack("!6s6sH", frame[:14])
print("Ethernet", src.hex(":"), "->", dst.hex(":"), f"type=0x{ethertype:04x}")
packet = frame[14:]

# Internet layer: header length lives in the low 4 bits of byte 0
ihl = (packet[0] & 0x0F) * 4
ttl, proto = packet[8], packet[9]
s_ip, d_ip = ipaddress.ip_address(packet[12:16]), ipaddress.ip_address(packet[16:20])
print("IPv4    ", s_ip, "->", d_ip, f"ttl={ttl} proto={proto} header={ihl}B")
segment = packet[ihl:]

# Transport layer: ports, sequence numbers, header length, flags
sport, dport, seq, ack, off_flags = struct.unpack("!HHIIH", segment[:14])
thl = (off_flags >> 12) * 4
flags = off_flags & 0x3F
print("TCP     ", sport, "->", dport, f"seq={seq} ack={ack} flags=0x{flags:02x} header={thl}B")

# Application layer: whatever is left
print("HTTP    ", segment[thl:].split(b"\r\n")[0].decode())

Output:

Ethernet 66:77:88:99:aa:bb -> 00:11:22:33:44:55 type=0x0800
IPv4     192.168.1.20 -> 203.0.113.10 ttl=64 proto=6 header=20B
TCP      54321 -> 80 seq=1000 ack=5001 flags=0x18 header=20B
HTTP     GET / HTTP/1.1

The non-obvious lines are the ones that make each layer self-describing. EtherType 0x0800 tells the receiver "the payload is IPv4" (0x86dd would be IPv6, 0x0806 ARP). The IP proto field value 6 says "the payload is TCP" (17 would be UDP, 1 ICMP). Header lengths are variable, so both IP and TCP store their own length, in 4-byte words, which is why the code multiplies by 4. Flags 0x18 are PSH and ACK, covered in TCP Handshake & Control Flags. This demultiplexing chain, type field by type field, is exactly what the kernel does for every packet.

Debugging Layer by Layer#

The model is most useful as a checklist. Start at the bottom and stop at the first layer that fails:

# Link: is the interface up and does it have a carrier?
ip link show eth0          # look for "state UP"
ip neigh                   # is the gateway's MAC resolved (REACHABLE/STALE) or FAILED?

# Internet: can packets reach the gateway and beyond?
ip route get 1.1.1.1       # which interface and gateway will be used
ping -c 3 1.1.1.1          # raw IP reachability (ICMP may be filtered, so not proof)
traceroute -n 1.1.1.1      # where along the path it stops

# Transport: does the port accept a connection?
nc -vz example.com 443     # "succeeded" means the TCP handshake completed

# Application: does the protocol work?
curl -sv https://example.com -o /dev/null   # DNS, TCP, TLS and HTTP in one trace

On Windows the equivalents are ipconfig /all, arp -a, route print, tracert, and Test-NetConnection example.com -Port 443.

Reading the results in layer terms turns guesses into diagnoses:

  • ping 1.1.1.1 works but ping example.com fails: the network is fine; name resolution (application layer, DNS) is broken.
  • nc reports "connection refused": IP routing works and the host answered with a TCP reset. Nothing listens on that port.
  • nc hangs until timeout: packets are being dropped, usually by a firewall or security group.
  • nc succeeds but curl fails with a certificate error: transport is fine; the problem is in TLS.

TCP/IP vs. OSI#

The OSI model has seven layers: Physical, Data Link, Network, Transport, Session, Presentation, Application. TCP/IP folds Session, Presentation and Application into one Application layer, and Physical plus Data Link into the Link layer.

OSI TCP/IP Typical device or software
7 Application, 6 Presentation, 5 Session Application browsers, web servers, TLS libraries
4 Transport Transport OS kernel TCP/UDP stack, L4 load balancers
3 Network Internet routers, firewalls, IP stack
2 Data Link, 1 Physical Link switches, NICs, Wi-Fi access points, cables

The OSI names are worth knowing because vendor documentation, certifications and product categories ("L7 firewall") use them. The TCP/IP layering is how the code is actually structured: the kernel owns transport and below, user-space programs own the application layer.

Where the Model Breaks Down#

The clean four-layer story gets muddy at the edges:

  • TLS sits between application and transport. It runs in user space on top of TCP but provides a secure channel to the application, so people half-jokingly call it "Layer 5.5". See The TLS Handshake.
  • QUIC is a transport protocol (streams, retransmission, congestion control) implemented in user space on top of UDP, with TLS 1.3 built in. HTTP/3 runs on it. See TCP vs UDP.
  • Tunnels and overlays (VXLAN, WireGuard, IPsec, GRE) carry a whole Ethernet frame or IP packet as the payload of another UDP or IP packet, so a capture shows the stack twice.
  • ARP lives between link and internet, and ICMP is carried inside IP yet serves IP itself.

Treat the model as a map, not the territory. It is the fastest way to orient yourself while debugging, but real packets sometimes ignore the neat boundaries, and the tunnel case is where MTU and firewall surprises usually hide.

Practice#

Run tcpdump -n -e -c 5 port 443 (or capture in Wireshark) while loading any HTTPS page on your own machine. For one packet, identify the source and destination MAC, the IP addresses, the ports and the TCP flags, then explain why the destination MAC belongs to your router rather than the web server.