COMPUTER NETWORKS / 2. NETWORK LAYER — IP

Network Layer — IP Addressing & Routing

How packets find their way across thousands of routers to any point on Earth


EXPLANATION

The Network Layer's job is routing — getting packets from any source to any destination across multiple networks. It uses IP addresses to identify devices globally.

IPv4 addresses:
• 32-bit numbers written as four 8-bit octets in decimal: 192.168.1.100
• Total space: 2³² = ~4.3 billion addresses (already exhausted, hence NAT and IPv6)
• Divided into two parts: Network ID + Host ID, determined by the subnet mask

Subnetting — dividing a large network into smaller ones:
• CIDR notation: 192.168.1.0/24 — the /24 means the first 24 bits are the network ID
• /24 = subnet mask 255.255.255.0 → 256 addresses, 254 usable hosts
• /16 = 65536 addresses. /8 = 16 million. /32 = single host
• Network address (all host bits = 0): 192.168.1.0 — identifies the network
• Broadcast address (all host bits = 1): 192.168.1.255 — sends to all hosts

Private vs Public IP ranges:
• 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 → private, not routed on internet
• NAT (Network Address Translation) maps many private IPs to one public IP
• This is why your home has one public IP but all devices can access the internet

IPv4 Packet Header (20 bytes minimum):
• Version, IHL, DSCP, Total Length
• TTL (Time To Live) → decremented by 1 at each router. Reaches 0 → packet dropped → ICMP Time Exceeded sent back. This is how traceroute works.
• Protocol (1=ICMP, 6=TCP, 17=UDP)
• Source IP, Destination IP

Routing: every router has a routing table. For each incoming packet, it checks the destination IP against the table, finds the best match (longest prefix match), and forwards to the next hop. This continues hop by hop until the packet reaches its destination.

ICMP (Internet Control Message Protocol):
• Layer 3 control protocol — used by ping and traceroute
• ping sends ICMP Echo Request → destination replies with Echo Reply
• traceroute sends packets with increasing TTL. Each router that drops a packet (TTL=0) sends back an ICMP Time Exceeded, revealing itself.

DIAGRAM

IPv4 HEADER (simplified):
  ┌────────┬────────┬────────────────────┬─────────────────────┐
  │Version │  IHL   │    Total Length    │       TTL           │
  ├────────┴────────┴────────────────────┼─────────────────────┤
  │       Protocol (TCP=6, UDP=17)       │   Header Checksum   │
  ├──────────────────────────────────────┴─────────────────────┤
  │                   Source IP Address                        │
  ├────────────────────────────────────────────────────────────┤
  │                 Destination IP Address                     │
  └────────────────────────────────────────────────────────────┘

  SUBNETTING: 192.168.1.0/24
  192.168.1.  0   ← Network address  (do not assign)
  192.168.1.  1   ← Usually gateway (your router)
  192.168.1. 2-254 ← Usable hosts
  192.168.1.255   ← Broadcast address

  ROUTING (each router does this):
  Packet dst: 142.250.80.46 (google.com)
  Routing table:
    10.0.0.0/8     → LAN
    0.0.0.0/0      → 203.0.113.1 (default gateway = your ISP)
  → No specific match → forward to ISP → ISP forwards toward Google

CODE

PYTHON
1import socket
2import struct
3import ipaddress
4
5# ── IP address manipulation ────────────────────────────
6network = ipaddress.IPv4Network("192.168.1.0/24")
7print(f"Network: {network.network_address}")
8print(f"Broadcast: {network.broadcast_address}")
9print(f"Netmask: {network.netmask}")
10print(f"Hosts: {network.num_addresses - 2}")
11
12# First 5 hosts
13for ip in list(network.hosts())[:5]:
14 print(f" {ip}")
15
16# ── Check if IP is in a subnet ─────────────────────────
17def is_private(ip: str) -> bool:
18 return ipaddress.IPv4Address(ip).is_private
19
20print(is_private("192.168.1.1")) # True
21print(is_private("8.8.8.8")) # False
22
23# ── ICMP Ping (raw socket — requires root) ─────────────
24import os
25import time
26
27def ping(host: str, count: int = 4):
28 """Simple ping using system command"""
29 for i in range(count):
30 start = time.time()
31 result = os.system(f"ping -c 1 -W 1 {host} > /dev/null 2>&1")
32 elapsed = (time.time() - start) * 1000
33 status = "✓" if result == 0 else "✗"
34 print(f" [{status}] {host} {elapsed:.1f}ms")
35
36ping("8.8.8.8") # Google DNS
37ping("1.1.1.1") # Cloudflare DNS
38
39# ── DNS resolution ─────────────────────────────────────
40def resolve(hostname: str):
41 try:
42 results = socket.getaddrinfo(hostname, None)
43 ips = list({r[4][0] for r in results})
44 print(f"{hostname} {', '.join(ips)}")
45 except socket.gaierror as e:
46 print(f"DNS failed: {e}")
47
48resolve("google.com")
49resolve("github.com")
← PREV1. Physical & Data LinkNEXT →3. Transport Layer — TCP & UDP