Why This Matters
A TCP connection to 93.184.216.34:443 is not a direct wire. Your host emits IP packets; each router inspects the destination address, decrements an 8-bit TTL or hop-limit field, and chooses one outgoing interface from its forwarding table. Any packet can be dropped, duplicated, or arrive after a later packet.
The application does not see that chaos when it reads from a TCP socket. TCP turns packets into a single ordered byte stream. UDP exposes datagrams with far fewer promises. Choosing between them changes retry logic, latency behavior, load balancer design, and failure modes.
Core Definitions
IP packet
An IP packet is the network-layer unit routed across an internetwork. IPv4 uses 32-bit addresses such as 192.0.2.17. IPv6 uses 128-bit addresses such as 2001:db8:85a3::8a2e:370:7334. IP names a source, a destination, and a next protocol, but it does not promise delivery.
Transport segment or datagram
TCP sends segments and UDP sends datagrams inside IP packets. TCP provides a byte stream with ordering, retransmission, duplicate suppression, and flow control. UDP preserves message boundaries but provides no delivery, ordering, or duplicate suppression guarantee.
Port number
A port is a 16-bit transport-layer demultiplexing field. TCP port 443 and UDP port 443 are separate namespaces. Ports 0 through 1023 are well-known ports by convention and operating-system policy.
Forwarding information base
The FIB is the router's data-plane table used for packet forwarding. For IP, lookup is by longest-prefix match on the destination address. Routing protocols populate tables, but per-packet forwarding uses the FIB.
Addresses and Packet Headers
IPv4 addresses are 32-bit integers usually written in dotted decimal. The address 192.168.1.10 is four octets:
decimal: 192 168 1 10
hex: c0 a8 01 0a
bits: 11000000 10101000 00000001 00001010
IPv6 addresses are 128-bit integers written as eight 16-bit hexadecimal groups. One run of all-zero groups can be compressed with ::.
full: 2001:0db8:0000:0000:0000:ff00:0042:8329
compressed: 2001:db8::ff00:42:8329
bytes: 20 01 0d b8 00 00 00 00 00 00 ff 00 00 42 83 29
An IPv4 header without options is 20 bytes. This example is an IPv4 packet carrying TCP from 192.168.1.10 to 93.184.216.34:
45 00 00 54 1c 46 40 00 40 06 b1 e6 c0 a8 01 0a 5d b8 d8 22
Field decoding:
0x45 version 4, IHL 5 words, header length 20 bytes
0x00 DSCP/ECN
0x0054 total length 84 bytes
0x1c46 identification
0x4000 flags and fragment offset, DF set, offset 0
0x40 TTL 64
0x06 protocol 6, TCP
0xb1e6 IPv4 header checksum
0xc0a8010a source 192.168.1.10
0x5db8d822 destination 93.184.216.34
IPv4 has a header checksum. Routers must update it when they decrement TTL. IPv6 removed the IP header checksum, relying on link-layer checks and transport checksums. IPv6 also replaces TTL with Hop Limit and uses a fixed 40-byte base header.
The protocol field in IPv4, or next header in IPv6, selects the next parser. Common values are 1 for ICMPv4, 6 for TCP, and 17 for UDP.
A small C parser for the fixed IPv4 header makes the byte ordering visible:
#include <stdint.h>
#include <stdio.h>
#include <arpa/inet.h>
struct ipv4_min {
uint8_t vihl;
uint8_t dscp_ecn;
uint16_t total_len;
uint16_t ident;
uint16_t flags_frag;
uint8_t ttl;
uint8_t proto;
uint16_t checksum;
uint32_t src;
uint32_t dst;
};
int main(void) {
unsigned char b[20] = {
0x45,0x00,0x00,0x54,0x1c,0x46,0x40,0x00,0x40,0x06,
0xb1,0xe6,0xc0,0xa8,0x01,0x0a,0x5d,0xb8,0xd8,0x22
};
struct ipv4_min *h = (struct ipv4_min *)b;
printf("version=%u ihl=%u bytes\n", h->vihl >> 4, (h->vihl & 0x0f) * 4);
printf("len=%u ttl=%u proto=%u\n",
ntohs(h->total_len), h->ttl, h->proto);
printf("src=%08x dst=%08x\n", ntohl(h->src), ntohl(h->dst));
}
The casts above assume an unaligned load is allowed by the target machine. Production parsers usually copy or assemble fields byte by byte when portability matters.
Per-Hop Forwarding and Best-Effort Delivery
A router does not compute a full path for each packet. It performs a lookup on the destination address, chooses a next hop, emits the packet on an interface, and forgets it. If the packet is later lost, IP itself does not repair the loss.
Longest-prefix match chooses the most specific matching prefix. Suppose a router has this FIB:
prefix next hop
0.0.0.0/0 isp-a
10.0.0.0/8 datacenter-core
10.4.0.0/16 rack-17
10.4.7.0/24 host-subnet-7
For destination 10.4.7.99, all four prefixes match. The selected row is 10.4.7.0/24, because 24 matching prefix bits beats 16, 8, and 0. For destination 10.4.9.2, the selected row is 10.4.0.0/16.
A packet with TTL 3 crossing routers R1, R2, and R3 changes like this:
host sends: TTL 3
R1 forwards: TTL 2
R2 forwards: TTL 1
R3 receives: TTL 1, decrements to 0, drops, may send ICMP Time Exceeded
Best-effort delivery permits at least four outcomes that application programmers must account for:
drop: packet never arrives
reorder: packet B arrives before packet A
duplicate: packet A arrives twice
corrupt: detected by checksum and discarded by a layer that checks it
TCP repairs many of these for a live connection. UDP does not. IP fragmentation is another IP feature, but modern applications usually avoid depending on it by keeping UDP payloads small or by using path MTU discovery.
Transport Layer Demultiplexing
The IP destination address gets a packet to a host or interface. The transport port gets payload to a socket. A TCP connection is identified by the protocol plus a four-tuple:
protocol: TCP
local address: 192.168.1.10
local port: 51514
remote address: 93.184.216.34
remote port: 443
A server can have many simultaneous TCP connections using local port 443, because the remote address and remote port differ. A listening socket accepts new connections; connected sockets carry the byte streams.
UDP demultiplexing is datagram oriented. A DNS server commonly listens on UDP port 53. If a client sends a 38-byte DNS query from 192.168.1.10:53000 to 8.8.8.8:53, the reply returns from 8.8.8.8:53 to 192.168.1.10:53000. The application receives one datagram, not a byte stream.
Well-known examples:
22/tcp SSH
53/udp DNS query in the common case
53/tcp DNS zone transfer and large responses
80/tcp HTTP
443/tcp HTTPS
443/udp QUIC over UDP
TCP does not preserve writes as messages. If one side writes 5 bytes and then 7 bytes, the peer might read 12 bytes at once, or 3 then 9, or other divisions. TCP promises byte order, not record boundaries.
ICMP, NAT, and Edge Behavior
ICMP carries control and diagnostic messages for IP. ping sends ICMP Echo Request and waits for Echo Reply. It measures reachability and round-trip time, but many networks rate-limit or block ICMP, so failed ping is not the same as failed TCP.
traceroute exploits TTL or Hop Limit. A probe with TTL 1 expires at the first router, which returns ICMP Time Exceeded. TTL 2 reaches the second router, and so on. A run might look like this:
probe TTL 1: reply from 192.168.1.1
probe TTL 2: reply from 10.20.0.1
probe TTL 3: reply from 203.0.113.5
probe TTL 4: reply from 93.184.216.34
NAT rewrites addresses, often ports too. Private IPv4 ranges are not routed on the public internet:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
Carrier-grade NAT commonly uses 100.64.0.0/10 between customers and provider NAT devices. A home NAT translation might store this mapping:
inside tuple outside tuple
192.168.1.10:51514 to 93.184.216.34:443 203.0.113.7:40001 to 93.184.216.34:443
Outbound packet rewrite:
before: src 192.168.1.10:51514, dst 93.184.216.34:443
after: src 203.0.113.7:40001, dst 93.184.216.34:443
Inbound reply rewrite:
before: src 93.184.216.34:443, dst 203.0.113.7:40001
after: src 93.184.216.34:443, dst 192.168.1.10:51514
The NAT must update IPv4, TCP, or UDP checksums after rewriting. NAT makes inbound connections harder, because no translation exists until a mapping is created. IPv6 reduces the address scarcity pressure that drove NAT, though firewalls still filter traffic.
The Model
Two invariants are enough to predict many packet traces.
First, IP forwarding is local:
At each router, TTL or Hop Limit is decremented. If the result is zero, the packet is dropped and an ICMP error may be returned. The router does not know whether the final application will read the data.
Second, transport delivery is a contract above IP. For TCP, if the connection remains established and data is acknowledged, the receiving application observes a prefix of the sender's byte stream in order:
for some increasing k. The application never sees byte B[100] before B[99] on the same TCP stream. For UDP, the receive operation returns individual datagrams that arrived and passed checksums. Missing datagrams are silent unless the application protocol detects them.
The practical split is this:
IP: where should this packet go next?
UDP: which process gets this datagram?
TCP: which process gets this ordered byte stream?
ICMP: what control message describes IP-level behavior?
That model is enough to debug many failures. A wrong default route breaks IP reachability. A closed port returns a transport-level error or times out. A NAT mapping timeout can kill an idle flow while both applications still believe their sockets exist.
Common Confusions
Treating TCP as a message protocol
Two calls to send() do not imply two calls to recv(). If a client sends "GET " and then "/ HTTP/1.1\r\n", the server might read "GET / HTTP/1.1\r\n" in one call. Application protocols over TCP need delimiters, length prefixes, or fixed-size records.
Thinking ports are part of IP
The IP header has addresses and a protocol number. TCP and UDP headers have ports. ICMP has no TCP or UDP port. A firewall rule matching 443/tcp is matching IP protocol 6 plus TCP destination port 443.
Assuming NAT is normal routing
A router forwards without changing end-host addresses. A NAT rewrites addresses and often ports, then stores state. If that state expires, the reverse packet has no mapping and is dropped.
Exercises
Problem
Decode this IPv4 header prefix and give version, header length, total length, TTL, protocol, source, and destination.
45 00 00 28 00 7b 40 00 3f 11 00 00 0a 00 00 05 c0 00 02 35
Problem
A router has the following FIB. Which next hop is selected for 172.16.9.200 and for 172.20.1.4?
0.0.0.0/0 isp
172.16.0.0/12 corp
172.16.8.0/21 lab
172.16.9.0/24 gpu-lab
Problem
A NAT has public address 198.51.100.9. It creates this mapping for an outbound TCP connection:
inside: 192.168.1.44:51000 to 93.184.216.34:443
outside: 198.51.100.9:40017 to 93.184.216.34:443
Write the source and destination address-port pairs after NAT for the outbound packet and after NAT for the inbound reply.
References
Canonical:
- Stevens and Fall, TCP/IP Illustrated, Volume 1: The Protocols (2011), ch. 1, 3, 5, 8, 10, 13, 17, covers layering, IP, ICMP, UDP, and TCP behavior
- Tanenbaum and Wetherall, Computer Networks (2011), ch. 5-6, covers network-layer forwarding and transport protocols
- Stevens, Fenner, and Rudoff, UNIX Network Programming, Volume 1 (2004), ch. 1-3, 5, 8, covers sockets, TCP clients and servers, and UDP
- Comer, Internetworking with TCP/IP, Volume 1 (6th ed., 2013), ch. 6-10, 12-13, covers IP addressing, forwarding, ICMP, UDP, and TCP
- Kurose and Ross, Computer Networking: A Top-Down Approach (8th ed., 2021), ch. 3-5, covers transport, network data plane, and routing context
Accessible:
- Brian Hall, Beej's Guide to Network Programming, sections on IP addresses, ports, TCP sockets, and UDP sockets
- Stanford CS144, Introduction to Computer Networking, public lecture notes on the internet, IP, TCP, and reliable byte streams
- IETF, RFC 791, RFC 8200, RFC 768, and RFC 9293, primary protocol specifications for IPv4, IPv6, UDP, and TCP