Networking Fundamentals & Debugging
OSI Model, TCP/IP, Packet Analysis, DNS, Port Scanning
Introduction
Before you can secure a network or debug a connectivity issue, you need to understand how networks actually work. This lesson covers the OSI and TCP/IP models, the Python tools for exploring networks, and the debugging utilities (tcpdump, Wireshark) that security engineers use daily. You'll also write an educational port scanner in Python, a key reconnaissance tool.
OSI Model, 7 Layers
The OSI (Open Systems Interconnection) model describes how data travels from an application through the network stack to another system. Each layer has a specific responsibility.
TCP/IP Model, 4 Layers
The TCP/IP model is the practical implementation used by the internet. It maps OSI layers to a simpler 4-layer model.
| TCP/IP Layer | OSI Equivalent | Key Protocols | Python Module |
|---|---|---|---|
| Application | L5–L7 | HTTP, HTTPS, DNS, SSH, SMTP | http.client, smtplib |
| Transport | L4 | TCP, UDP | socket |
| Internet | L3 | IP, ICMP, ARP | socket, scapy |
| Link | L1–L2 | Ethernet, Wi-Fi, ARP | scapy |
Python: Network Information & DNS
# network_info.py
import socket
import ipaddress
# ── Basic socket information ─────────────────────────────────
hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
print(f"Hostname: {hostname}")
print(f"Local IP: {local_ip}")
# ── DNS resolution ────────────────────────────────────────────
domain = "python.org"
ip = socket.gethostbyname(domain)
print(f"\n{domain} → {ip}")
# Reverse lookup
try:
reverse = socket.gethostbyaddr(ip)
print(f"{ip} → {reverse[0]}")
except socket.herror:
print(f"No reverse DNS for {ip}")
# Get all IPs (IPv4 + IPv6)
results = socket.getaddrinfo(domain, 443, proto=socket.IPPROTO_TCP)
print(f"\nAll addresses for {domain}:443 (HTTPS):")
for family, _type, _proto, _canonname, sockaddr in results:
family_name = "IPv6" if family == socket.AF_INET6 else "IPv4"
print(f" {family_name}: {sockaddr[0]}")
# ── IP address utilities ─────────────────────────────────────
network = ipaddress.ip_network("192.168.1.0/24", strict=False)
print(f"\nNetwork: {network}")
print(f"Hosts: {network.num_addresses - 2} (first: {list(network.hosts())[0]})")
print(f"Is private: {network.is_private}")
# Check if IP is in network
test_ip = ipaddress.ip_address("192.168.1.100")
print(f"192.168.1.100 in {network}: {test_ip in network}")Expected Output:
Hostname: my-machine Local IP: 192.168.1.42 python.org → 151.101.128.223 151.101.128.223 → dualstack.python.map.fastly.net All addresses for python.org:443 (HTTPS): IPv4: 151.101.128.223 IPv6: 2a04:4e42:1e::223 Network: 192.168.1.0/24 Hosts: 254 (first: 192.168.1.1) Is private: True 192.168.1.100 in 192.168.1.0/24: True
tcpdump & Wireshark Cheat Sheet
# tcpdump, capture and filter packets on the command line # Capture all traffic on interface eth0 sudo tcpdump -i eth0 # Capture only HTTP/HTTPS traffic sudo tcpdump -i eth0 'tcp port 80 or tcp port 443' # Capture traffic to/from specific host sudo tcpdump -i eth0 host 192.168.1.100 # Save capture to file for Wireshark analysis sudo tcpdump -i eth0 -w capture.pcap # Read saved capture sudo tcpdump -r capture.pcap # Show packet contents in ASCII sudo tcpdump -i eth0 -A 'tcp port 80' # Show packet contents in hex+ASCII (very detailed) sudo tcpdump -i eth0 -X 'tcp port 8080' # Capture DNS queries sudo tcpdump -i eth0 'udp port 53' # Filter by source IP and port sudo tcpdump -i eth0 'src 10.0.0.1 and dst port 443' # ── Wireshark filter expressions ───────────────────────────── # ip.addr == 192.168.1.100 → All traffic to/from IP # tcp.port == 443 → HTTPS traffic # http.request.method == "POST" → HTTP POST requests only # tcp.flags.syn == 1 → TCP SYN packets (new connections) # frame contains "password" → Frames with the word "password"
Python: Port Scanner (Educational)
Authorized Use Only
Only scan systems you own or have explicit written permission to test. Unauthorized port scanning is illegal in most jurisdictions. The following script is for learning on your own localhost or lab environment.
# port_scanner.py, Educational port scanner for authorized use only
import socket
import concurrent.futures
from datetime import datetime
COMMON_PORTS = {
21: "FTP", 22: "SSH", 23: "Telnet", 25: "SMTP",
53: "DNS", 80: "HTTP", 110: "POP3", 143: "IMAP",
443: "HTTPS", 3306: "MySQL", 5432: "PostgreSQL",
6379: "Redis", 8080: "HTTP-Alt", 8443: "HTTPS-Alt",
27017: "MongoDB",
}
def scan_port(host: str, port: int, timeout: float = 1.0) -> dict | None:
"""Return port info if open, None if closed."""
try:
with socket.create_connection((host, port), timeout=timeout):
service = COMMON_PORTS.get(port, "unknown")
return {"port": port, "service": service, "status": "OPEN"}
except (socket.timeout, ConnectionRefusedError, OSError):
return None
def scan_host(host: str, ports: list[int], workers: int = 50) -> list[dict]:
"""Scan a host for open ports using a thread pool."""
open_ports = []
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
futures = {executor.submit(scan_port, host, p): p for p in ports}
for future in concurrent.futures.as_completed(futures):
result = future.result()
if result:
open_ports.append(result)
return sorted(open_ports, key=lambda x: x["port"])
# ── Scan localhost only (safe for educational use) ────────────
target = "127.0.0.1"
ports_to_scan = list(COMMON_PORTS.keys())
print(f"Scanning {target}, {datetime.now().strftime('%H:%M:%S')}")
print(f"Ports: {len(ports_to_scan)}")
print("-" * 40)
results = scan_host(target, ports_to_scan)
if results:
for r in results:
print(f" PORT {r['port']:5d}/tcp OPEN {r['service']}")
else:
print(" No open ports found")
print(f"\nScan complete: {len(results)} open port(s) found")Expected Output:
Scanning 127.0.0.1, 14:23:07 Ports: 15 ---------------------------------------- PORT 22/tcp OPEN SSH PORT 80/tcp OPEN HTTP PORT 5432/tcp OPEN PostgreSQL PORT 6379/tcp OPEN Redis Scan complete: 4 open port(s) found
Key Takeaways
- OSI has 7 layers, each layer handles a specific function and security controls exist at every layer
- TCP/IP simplifies to 4 layers, Application, Transport, Internet, Link, the internet actually runs on this
- Python's
socketmodule, provides direct access to L4 (TCP/UDP) and lower via raw sockets - tcpdump is your first debugging tool, use it to see exactly what traffic is on the wire
- Port scanning reveals the attack surface, security engineers regularly scan their own infrastructure
- ThreadPoolExecutor speeds up I/O-bound scanning, concurrent connections dramatically reduce scan time
What's Next?
Lesson 6 goes deep into socket programming, building real TCP and UDP servers and clients in Python.
- TCP socket server and client, full working examples with output
- UDP sockets, connectionless communication
- Multi-client server with threading, handling concurrent connections
- Async sockets with asyncio, modern non-blocking I/O