Cheat sheet — Network Programming¶
Companion to Module 06 — Network Programming · CC BY 4.0 — print it, pin it, share it.
Last reviewed: 2026-07
Scan and send only against systems you own or have explicit written permission to test.
socket — a TCP port probe¶
import socket
def scan(host, port, timeout=1.0):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(timeout) # without this a filtered port hangs forever
code = s.connect_ex((host, port)) # returns 0 on success; error code otherwise
return code == 0 # True = OPEN
connect_ex vs connect¶
s.connect((host, port)) # raises ConnectionRefusedError / TimeoutError on failure
s.connect_ex((host, port)) # returns an errno int instead of raising — cleaner for scanning
# 0 = open · 111/ECONNREFUSED = closed (RST) · timeout = filtered (packet dropped)
Banner grabbing — read what the service announces¶
def grab_banner(host, port, timeout=2.0):
with socket.socket() as s: # AF_INET/SOCK_STREAM are the defaults
s.settimeout(timeout)
s.connect((host, port))
try:
data = s.recv(1024) # SSH/SMTP/FTP announce first
except socket.timeout:
s.sendall(b"HEAD / HTTP/1.0\r\n\r\n") # HTTP is probe-first — speak, then read
data = s.recv(1024)
return data.decode("utf-8", errors="replace") # never assume valid UTF-8 off the wire
Error cases a real scan hits¶
try:
...
except ConnectionRefusedError: # RST — port is CLOSED
...
except (socket.timeout, TimeoutError): # no reply — port is FILTERED
...
except OSError: # network unreachable, no route, etc.
...
scapy — layers stack with /¶
from scapy.all import IP, TCP, ICMP, Ether, Raw, sr1, send, sniff, rdpcap, wrpcap
pkt = IP(dst="10.0.0.9") / TCP(dport=22, flags="S") # each layer stacks with /
pkt = Ether() / IP() / TCP() / Raw(load=b"data") # full stack, link layer up
pkt.show() # dump every field at every layer
pkt[TCP].flags # index by layer class to read a field
scapy — send and receive¶
ans = sr1(IP(dst="10.0.0.9") / TCP(dport=22, flags="S"), timeout=2, verbose=0)
# sr1 = send 1 packet, return the FIRST reply. send() = fire-and-forget (no reply captured).
if ans and ans.haslayer(TCP):
if ans[TCP].flags == "SA": # SYN-ACK -> OPEN
open_port = True
elif ans[TCP].flags == "R": # RST -> CLOSED
open_port = False
# ans is None on no reply -> FILTERED
scapy — capture & pcap I/O¶
pkts = sniff(count=10, filter="tcp port 22", timeout=5) # BPF filter — same syntax as tcpdump
sniff(prn=lambda p: p.summary(), filter="tcp", store=False) # callback per packet, don't buffer
wrpcap("capture.pcap", pkts) # write a pcap
pkts = rdpcap("capture.pcap") # read one back (post-process Wireshark/tcpdump traces)
for p in pkts:
if p.haslayer(TCP):
p[IP].src, p[TCP].dport
BPF filter quick reference (sniff filter=)¶
tcp port 22 tcp traffic on port 22
host 10.0.0.9 to/from that host
src host 10.0.0.9 source only dst port 443 destination port only
tcp and not port 22 combine with and / or / not
tcp[tcpflags] & tcp-syn != 0 SYN-flagged packets
Gotchas worth remembering¶
- Authorization first, always. A scanner pointed at the wrong subnet is an incident; scapy will send whatever you tell it, malformed packets included, with no guardrail. Stay inside written scope.
filtered≠closed≠open. ARSTmeans closed, aSYN-ACKmeans open, and silence (dropped packet) means filtered — and that silence is itself intel about a firewall. Read the response, don't just tally opens.- Always
settimeout(). Without it a filtered port makesconnect/recvhang indefinitely and your scan never finishes. One or two seconds is plenty on a LAN. - Not every service speaks first. SSH/SMTP/FTP announce on connect; HTTP and TLS ports don't —
recvon an HTTPS port returns TLS hello bytes, not plaintext. Probe-first when the recv times out. - Decode wire bytes with
errors="replace". Banners are arbitrary bytes; a plain.decode()raisesUnicodeDecodeErroron the first non-UTF-8 byte and crashes the grab. - Raw scapy send/sniff needs root (raw sockets).
connect_ex-based scanning does not — reach for plainsocketwhen you only need open/closed and don't want privileges.
Comments
Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).